Snapshot of commit d5ec1d5018ed24f1b4f32b1d09df6dbd7e2fc425

from branch master of git://git.jetbrains.org/idea/community.git
diff --git a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java
new file mode 100644
index 0000000..240e7e5
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java
@@ -0,0 +1,736 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight;
+
+import com.intellij.codeInsight.highlighting.HighlightUsagesHandler;
+import com.intellij.ide.DataManager;
+import com.intellij.injected.editor.EditorWindow;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.command.undo.UndoManager;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.editor.actionSystem.EditorActionManager;
+import com.intellij.openapi.editor.actionSystem.TypedAction;
+import com.intellij.openapi.editor.impl.DocumentImpl;
+import com.intellij.openapi.editor.impl.EditorImpl;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.fileEditor.TextEditor;
+import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiPackage;
+import com.intellij.psi.impl.source.PostprocessReformattingAspect;
+import com.intellij.psi.search.ProjectScope;
+import com.intellij.testFramework.PsiTestCase;
+import com.intellij.testFramework.PsiTestData;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.testFramework.VfsTestUtil;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * @author Mike
+ */
+public abstract class CodeInsightTestCase extends PsiTestCase {
+  protected Editor myEditor;
+
+  protected Editor createEditor(VirtualFile file) {
+    final FileEditorManager instance = FileEditorManager.getInstance(myProject);
+
+    if (file.getFileType().isBinary()) return null;
+
+    Editor editor = instance.openTextEditor(new OpenFileDescriptor(myProject, file, 0), false);
+    ((EditorImpl)editor).setCaretActive();
+    return editor;
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    FileEditorManager editorManager = FileEditorManager.getInstance(myProject);
+    VirtualFile[] openFiles = editorManager.getOpenFiles();
+    for (VirtualFile openFile : openFiles) {
+      editorManager.closeFile(openFile);
+    }
+    myEditor = null;
+    super.tearDown();
+  }
+
+  @Override
+  protected PsiTestData createData() {
+    return new CodeInsightTestData();
+  }
+
+  public static final String CARET_MARKER = "<caret>";
+  @NonNls public static final String SELECTION_START_MARKER = "<selection>";
+  @NonNls public static final String SELECTION_END_MARKER = "</selection>";
+
+  protected void configureByFile(@NonNls String filePath) throws Exception {
+    configureByFile(filePath, null);
+  }
+  protected VirtualFile configureByFiles(@Nullable String projectRoot,String... files) throws Exception {
+    final VirtualFile[] vFiles = new VirtualFile[files.length];
+    for (int i = 0; i < files.length; i++) {
+      String path = files[i];
+      final String fullPath = FileUtil.toSystemIndependentName(getTestDataPath() + path);
+      VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath);
+      vFiles[i] = vFile;
+      assertNotNull("file " + fullPath + " not found", vFile);
+    }
+
+    File projectFile = projectRoot == null ? null : new File(getTestDataPath() + projectRoot);
+
+    return configureByFiles(projectFile, vFiles);
+  }
+  protected VirtualFile configureByFile(@NonNls String filePath, String projectRoot) throws Exception {
+    String fullPath = getTestDataPath() + filePath;
+
+    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/'));
+    assertNotNull("file " + fullPath + " not found", vFile);
+
+    File projectFile = projectRoot == null ? null : new File(getTestDataPath() + projectRoot);
+
+    return configureByFile(vFile, projectFile);
+  }
+
+  protected PsiFile configureByText(final FileType fileType, @NonNls final String text) throws Exception {
+    return configureByText(fileType, text, null);
+  }
+
+  protected PsiFile configureByText(final FileType fileType, @NonNls final String text, @Nullable String _extension) throws Exception {
+    final String extension = _extension == null ? fileType.getDefaultExtension():_extension;
+
+    File dir = createTempDirectory();
+    final File tempFile = FileUtil.createTempFile(dir, "aaa", "." + extension, true);
+    final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
+    if (fileTypeManager.getFileTypeByExtension(extension) != fileType) {
+      new WriteCommandAction(getProject()) {
+        @Override
+        protected void run(Result result) throws Exception {
+          fileTypeManager.associateExtension(fileType, extension);
+        }
+      }.execute();
+    }
+    final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempFile);
+    assert vFile != null;
+    VfsUtil.saveText(vFile, text);
+
+    final VirtualFile vdir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir);
+
+    PsiTestUtil.addSourceRoot(myModule, vdir);
+
+    configureByExistingFile(vFile);
+
+    assertEquals(fileType, myFile.getVirtualFile().getFileType());
+    return myFile;
+  }
+
+
+  @Override
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath();
+  }
+
+  protected void configureByFile(final VirtualFile vFile) throws IOException {
+    configureByFile(vFile, null);
+  }
+
+  protected void configureByExistingFile(final VirtualFile virtualFile) {
+    myFile = null;
+    myEditor = null;
+
+    final Editor editor = createEditor(virtualFile);
+
+    final Document document = editor.getDocument();
+    final EditorInfo editorInfo = new EditorInfo(document.getText());
+
+    final String newFileText = editorInfo.getNewFileText();
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        if (!document.getText().equals(newFileText)) {
+          document.setText(newFileText);
+        }
+
+        PsiFile file = myPsiManager.findFile(virtualFile);
+        if (myFile == null) myFile = file;
+
+        if (myEditor == null) myEditor = editor;
+
+        editorInfo.applyToEditor(editor);
+      }
+    });
+
+
+    PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+  }
+
+  protected VirtualFile configureByFiles(@Nullable final File rawProjectRoot, final VirtualFile... vFiles) throws IOException {
+    myFile = null;
+    myEditor = null;
+
+    final File toDirIO = createTempDirectory();
+    final VirtualFile toDir = getVirtualFile(toDirIO);
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          final ModuleRootManager rootManager = ModuleRootManager.getInstance(myModule);
+          final ModifiableRootModel rootModel = rootManager.getModifiableModel();
+          if (clearModelBeforeConfiguring()) {
+            rootModel.clear();
+          }
+
+          // auxiliary files should be copied first
+          VirtualFile[] reversed = ArrayUtil.reverseArray(vFiles);
+          final LinkedHashMap<VirtualFile, EditorInfo> editorInfos;
+          if (rawProjectRoot != null) {
+            final File projectRoot = rawProjectRoot.getCanonicalFile();
+            FileUtil.copyDir(projectRoot, toDirIO);
+            VirtualFile fromDir = getVirtualFile(projectRoot);
+            editorInfos =
+              copyFilesFillingEditorInfos(fromDir, toDir, ContainerUtil.map2Array(reversed, String.class, new Function<VirtualFile, String>() {
+                @Override
+                public String fun(final VirtualFile s) {
+                  return s.getPath().substring(projectRoot.getPath().length());
+                }
+              }));
+
+            toDir.refresh(false, true);
+          }
+          else {
+            editorInfos = new LinkedHashMap<VirtualFile, EditorInfo>();
+            for (final VirtualFile vFile : reversed) {
+              VirtualFile parent = vFile.getParent();
+              assert parent.isDirectory() : parent;
+              editorInfos.putAll(copyFilesFillingEditorInfos(parent, toDir, vFile.getName()));
+            }
+          }
+
+          boolean sourceRootAdded = false;
+          if (isAddDirToContentRoot()) {
+            final ContentEntry contentEntry = rootModel.addContentEntry(toDir);
+            if (isAddDirToSource()) {
+              sourceRootAdded = true;
+              contentEntry.addSourceFolder(toDir, isAddDirToTests());
+            }
+          }
+          doCommitModel(rootModel);
+          if (sourceRootAdded) {
+            sourceRootAdded(toDir);
+          }
+
+          openEditorsAndActivateLast(editorInfos);
+        }
+        catch (IOException e) {
+          LOG.error(e);
+        }
+      }
+    });
+
+
+    return toDir;
+  }
+
+  protected boolean isAddDirToTests() {
+    return false;
+  }
+
+  protected void doCommitModel(final ModifiableRootModel rootModel) {
+    rootModel.commit();
+  }
+
+  protected void sourceRootAdded(final VirtualFile dir) {
+  }
+
+  protected LinkedHashMap<VirtualFile, EditorInfo> copyFilesFillingEditorInfos(String testDataFromDir,
+                                                                               final VirtualFile toDir,
+                                                                               final String... relativePaths) throws IOException {
+    if (!testDataFromDir.startsWith("/")) testDataFromDir = "/" + testDataFromDir;
+    return copyFilesFillingEditorInfos(LocalFileSystem.getInstance().refreshAndFindFileByPath(getTestDataPath() + testDataFromDir), toDir, relativePaths);
+  }
+
+  protected LinkedHashMap<VirtualFile, EditorInfo> copyFilesFillingEditorInfos(final VirtualFile fromDir, final VirtualFile toDir, final String... relativePaths) throws IOException {
+    LinkedHashMap<VirtualFile, EditorInfo> editorInfos = new LinkedHashMap<VirtualFile, EditorInfo>();
+
+    List<OutputStream> streamsToClose = new ArrayList<OutputStream>();
+
+    for (String relativePath : relativePaths) {
+      if (relativePath.startsWith("/")) {
+        relativePath = relativePath.substring(1);
+      }
+      final VirtualFile fromFile = fromDir.findFileByRelativePath(relativePath);
+      assertNotNull(fromDir.getPath() + "/" + relativePath, fromFile);
+      VirtualFile toFile = toDir.findFileByRelativePath(relativePath);
+      if (toFile == null) {
+        final File file = new File(toDir.getPath(), relativePath);
+        FileUtil.createIfDoesntExist(file);
+        toFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
+        assertNotNull(file.getCanonicalPath(), toFile);
+      }
+      toFile.putUserData(VfsTestUtil.TEST_DATA_FILE_PATH, FileUtil.toSystemDependentName(fromFile.getPath()));
+      editorInfos.put(toFile, copyContent(fromFile, toFile, streamsToClose));
+    }
+
+    for(int i = streamsToClose.size() -1; i >= 0 ; --i) {
+      streamsToClose.get(i).close();
+    }
+    return editorInfos;
+  }
+
+  /*protected LinkedHashMap<VirtualFile, EditorInfo> copyFilesFillingEditorInfos(final VirtualFile fromDir, final VirtualFile toDir) throws IOException {
+    final LinkedHashMap<VirtualFile, EditorInfo> map = new LinkedHashMap<VirtualFile, EditorInfo>();
+    copyFilesFillingEditorInfos(fromDir, toDir, map);
+    return map;
+  }
+
+
+  private void copyFilesFillingEditorInfos(final VirtualFile fromDir, final VirtualFile toDir, LinkedHashMap<VirtualFile, EditorInfo> editorInfos) throws IOException {
+
+    List<OutputStream> streamsToClose = new ArrayList<OutputStream>();
+
+    final VirtualFile[] files = fromDir.getChildren();
+    for (final VirtualFile fromFile : files) {
+      if (fromFile.isDirectory()) {
+        copyFilesFillingEditorInfos(fromFile, toDir.createChildDirectory(this, fromFile.getName()), editorInfos);
+      } else {
+        final VirtualFile toFile = toDir.createChildData(this, fromFile.getName());
+        editorInfos.put(toFile, copyContent(fromFile, toFile, streamsToClose));
+      }
+    }
+
+    for(int i = streamsToClose.size() -1; i >= 0 ; --i) {
+      streamsToClose.get(i).close();
+    }
+  }*/
+
+  private EditorInfo copyContent(final VirtualFile from, final VirtualFile to, final List<OutputStream> streamsToClose) throws IOException {
+    byte[] content = from.getFileType().isBinary() ? from.contentsToByteArray(): null;
+    final String fileText = from.getFileType().isBinary() ? null : StringUtil.convertLineSeparators(VfsUtil.loadText(from));
+
+    EditorInfo editorInfo = fileText != null ? new EditorInfo(fileText) : null;
+    String newFileText = fileText != null ? editorInfo.getNewFileText() : null;
+    doWrite(newFileText, to, content, streamsToClose);
+    return editorInfo;
+  }
+
+  protected final void setActiveEditor(Editor editor) {
+    myEditor = editor;
+    myFile = getPsiFile(editor.getDocument());
+  }
+
+  protected List<Editor> openEditorsAndActivateLast(final LinkedHashMap<VirtualFile, EditorInfo> editorInfos) {
+    final List<Editor> list = openEditors(editorInfos);
+    setActiveEditor(list.get(list.size() - 1));
+    return list;
+  }
+
+  protected final List<Editor> openEditors(final LinkedHashMap<VirtualFile, EditorInfo> editorInfos) {
+    return ContainerUtil.map(editorInfos.keySet(), new Function<VirtualFile, Editor>() {
+      @Override
+      public Editor fun(final VirtualFile newVFile) {
+        PsiFile file = myPsiManager.findFile(newVFile);
+        if (myFile == null) myFile = file;
+
+        Editor editor = createEditor(newVFile);
+        if (myEditor == null) myEditor = editor;
+
+        EditorInfo editorInfo = editorInfos.get(newVFile);
+        if (editorInfo != null) {
+          editorInfo.applyToEditor(editor);
+        }
+        return editor;
+      }
+    });
+  }
+
+  private void doWrite(final String newFileText, final VirtualFile newVFile, final byte[] content, final List<OutputStream> streamsToClose) throws IOException {
+    if (newFileText != null) {
+      VfsUtil.saveText(newVFile, newFileText);
+    } else {
+      final OutputStream outputStream = newVFile.getOutputStream(this, -1, -1);
+      outputStream.write(content);
+      streamsToClose.add(outputStream);
+    }
+  }
+
+  protected boolean isAddDirToContentRoot() {
+    return true;
+  }
+
+  protected boolean isAddDirToSource() {
+    return true;
+  }
+
+  protected VirtualFile configureByFile(final VirtualFile vFile, final File projectRoot) throws IOException {
+    return configureByFiles(projectRoot, vFile);
+  }
+
+  protected boolean clearModelBeforeConfiguring() {
+    return false;
+  }
+
+  protected void setupCursorAndSelection(final Editor editor) {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        Document document = editor.getDocument();
+        final String text = document.getText();
+
+        int caretIndex = text.indexOf(CARET_MARKER);
+        int selStartIndex = text.indexOf(SELECTION_START_MARKER);
+        int selEndIndex = text.indexOf(SELECTION_END_MARKER);
+
+        final RangeMarker caretMarker = caretIndex >= 0 ? document.createRangeMarker(caretIndex, caretIndex) : null;
+        final RangeMarker selStartMarker = selStartIndex >= 0 ? document.createRangeMarker(selStartIndex, selStartIndex) : null;
+        final RangeMarker selEndMarker = selEndIndex >= 0 ? document.createRangeMarker(selEndIndex, selEndIndex) : null;
+
+        if (caretMarker != null) {
+          document.deleteString(caretMarker.getStartOffset(), caretMarker.getStartOffset() + CARET_MARKER.length());
+        }
+        if (selStartMarker != null) {
+          document.deleteString(selStartMarker.getStartOffset(), selStartMarker.getStartOffset() + SELECTION_START_MARKER.length());
+        }
+        if (selEndMarker != null) {
+          document.deleteString(selEndMarker.getStartOffset(), selEndMarker.getStartOffset() + SELECTION_END_MARKER.length());
+        }
+
+        final String newText = document.getText();
+
+        if (caretMarker != null) {
+          int caretLine = StringUtil.offsetToLineNumber(newText, caretMarker.getStartOffset());
+          int caretCol = caretMarker.getStartOffset() - StringUtil.lineColToOffset(newText, caretLine, 0);
+          LogicalPosition pos = new LogicalPosition(caretLine, caretCol);
+          editor.getCaretModel().moveToLogicalPosition(pos);
+        }
+
+        if (selStartMarker != null) {
+          editor.getSelectionModel().setSelection(selStartMarker.getStartOffset(), selEndMarker.getStartOffset());
+        }
+
+        PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+      }
+    });
+  }
+
+  @Override
+  protected void configure(String path, String dataName) throws Exception {
+    super.configure(path, dataName);
+
+    myEditor = createEditor(myFile.getVirtualFile());
+
+    CodeInsightTestData data = (CodeInsightTestData) myTestDataBefore;
+
+    LogicalPosition pos = new LogicalPosition(data.getLineNumber() - 1, data.getColumnNumber() - 1);
+    myEditor.getCaretModel().moveToLogicalPosition(pos);
+
+    int selectionEnd;
+    int selectionStart = selectionEnd = myEditor.getCaretModel().getOffset();
+
+    if (data.getSelectionStartColumnNumber() >= 0) {
+      selectionStart = myEditor.logicalPositionToOffset(new LogicalPosition(data.getSelectionEndLineNumber() - 1, data.getSelectionStartColumnNumber() - 1));
+      selectionEnd = myEditor.logicalPositionToOffset(new LogicalPosition(data.getSelectionEndLineNumber() - 1, data.getSelectionEndColumnNumber() - 1));
+    }
+
+    myEditor.getSelectionModel().setSelection(selectionStart, selectionEnd);
+  }
+
+  protected void checkResultByFile(@NonNls String filePath) throws Exception {
+    checkResultByFile(filePath, false);
+  }
+
+  protected void checkResultByFile(@NonNls final String filePath, final boolean stripTrailingSpaces) throws Exception {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        getProject().getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
+        if (stripTrailingSpaces) {
+          ((DocumentImpl)myEditor.getDocument()).stripTrailingSpaces();
+        }
+
+        PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+        String fullPath = getTestDataPath() + filePath;
+
+        final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/'));
+        assertNotNull("Cannot find file " + fullPath, vFile);
+        String ft = null;
+        try {
+          ft = VfsUtil.loadText(vFile);
+        }
+        catch (IOException e) {
+          throw new RuntimeException(e);
+        }
+
+        String fileText = StringUtil.convertLineSeparators(ft);
+        Document document = EditorFactory.getInstance().createDocument(fileText);
+
+        int caretIndex = fileText.indexOf(CARET_MARKER);
+        int selStartIndex = fileText.indexOf(SELECTION_START_MARKER);
+        int selEndIndex = fileText.indexOf(SELECTION_END_MARKER);
+
+        final RangeMarker caretMarker = caretIndex >= 0 ? document.createRangeMarker(caretIndex, caretIndex) : null;
+        final RangeMarker selStartMarker = selStartIndex >= 0 ? document.createRangeMarker(selStartIndex, selStartIndex) : null;
+        final RangeMarker selEndMarker = selEndIndex >= 0 ? document.createRangeMarker(selEndIndex, selEndIndex) : null;
+
+        if (caretMarker != null) {
+          document.deleteString(caretMarker.getStartOffset(), caretMarker.getStartOffset() + CARET_MARKER.length());
+        }
+        if (selStartMarker != null) {
+          document.deleteString(selStartMarker.getStartOffset(), selStartMarker.getStartOffset() + SELECTION_START_MARKER.length());
+        }
+        if (selEndMarker != null) {
+          document.deleteString(selEndMarker.getStartOffset(), selEndMarker.getStartOffset() + SELECTION_END_MARKER.length());
+        }
+
+        String newFileText = document.getText();
+        String newFileText1 = newFileText;
+        if (stripTrailingSpaces) {
+          Document document1 = EditorFactory.getInstance().createDocument(newFileText);
+          ((DocumentImpl)document1).stripTrailingSpaces();
+          newFileText1 = document1.getText();
+        }
+
+        if (myEditor instanceof EditorWindow) {
+          myEditor = ((EditorWindow)myEditor).getDelegate();
+          myFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(myEditor.getDocument());
+        }
+
+        String text = myFile.getText();
+        text = StringUtil.convertLineSeparators(text);
+
+        assertEquals("Text mismatch in file " + filePath, newFileText1, text);
+
+        if (caretMarker != null) {
+          int caretLine = StringUtil.offsetToLineNumber(newFileText, caretMarker.getStartOffset());
+          int caretCol = caretMarker.getStartOffset() - StringUtil.lineColToOffset(newFileText, caretLine, 0);
+
+          assertEquals("caretLine", caretLine + 1, myEditor.getCaretModel().getLogicalPosition().line + 1);
+          assertEquals("caretColumn", caretCol + 1, myEditor.getCaretModel().getLogicalPosition().column + 1);
+        }
+
+        if (selStartMarker != null && selEndMarker != null) {
+          int selStartLine = StringUtil.offsetToLineNumber(newFileText, selStartMarker.getStartOffset());
+          int selStartCol = selStartMarker.getStartOffset() - StringUtil.lineColToOffset(newFileText, selStartLine, 0);
+
+          int selEndLine = StringUtil.offsetToLineNumber(newFileText, selEndMarker.getEndOffset());
+          int selEndCol = selEndMarker.getEndOffset() - StringUtil.lineColToOffset(newFileText, selEndLine, 0);
+
+          assertEquals("selectionStartLine", selStartLine + 1,
+                       StringUtil.offsetToLineNumber(newFileText, myEditor.getSelectionModel().getSelectionStart()) + 1);
+
+          assertEquals("selectionStartCol", selStartCol + 1,
+                       myEditor.getSelectionModel().getSelectionStart() - StringUtil.lineColToOffset(newFileText, selStartLine, 0) + 1);
+
+          assertEquals("selectionEndLine", selEndLine + 1,
+                       StringUtil.offsetToLineNumber(newFileText, myEditor.getSelectionModel().getSelectionEnd()) + 1);
+
+          assertEquals("selectionEndCol", selEndCol + 1,
+                       myEditor.getSelectionModel().getSelectionEnd() - StringUtil.lineColToOffset(newFileText, selEndLine, 0) + 1);
+        }
+        else {
+          assertTrue("should has no selection, but was: ("+myEditor.getSelectionModel().getSelectionStart()+", "+myEditor.getSelectionModel().getSelectionEnd()+")",
+                     !myEditor.getSelectionModel().hasSelection());
+        }
+      }
+    });
+  }
+
+  @Override
+  protected void checkResult(String dataName) throws Exception {
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+    super.checkResult(dataName);
+
+    CodeInsightTestData data = (CodeInsightTestData) myTestDataAfter;
+
+    if (data.getColumnNumber() >= 0) {
+      assertEquals(dataName + ":caretColumn", data.getColumnNumber(), myEditor.getCaretModel().getLogicalPosition().column + 1);
+    }
+    if (data.getLineNumber() >= 0) {
+      assertEquals(dataName + ":caretLine", data.getLineNumber(), myEditor.getCaretModel().getLogicalPosition().line + 1);
+    }
+
+    int selectionStart = myEditor.getSelectionModel().getSelectionStart();
+    int selectionEnd = myEditor.getSelectionModel().getSelectionEnd();
+    LogicalPosition startPosition = myEditor.offsetToLogicalPosition(selectionStart);
+    LogicalPosition endPosition = myEditor.offsetToLogicalPosition(selectionEnd);
+
+    if (data.getSelectionStartColumnNumber() >= 0) {
+      assertEquals(dataName + ":selectionStartColumn", data.getSelectionStartColumnNumber(), startPosition.column + 1);
+    }
+    if (data.getSelectionStartLineNumber() >= 0) {
+      assertEquals(dataName + ":selectionStartLine", data.getSelectionStartLineNumber(), startPosition.line + 1);
+    }
+    if (data.getSelectionEndColumnNumber() >= 0) {
+      assertEquals(dataName + ":selectionEndColumn", data.getSelectionEndColumnNumber(), endPosition.column + 1);
+    }
+    if (data.getSelectionEndLineNumber() >= 0) {
+      assertEquals(dataName + ":selectionEndLine", data.getSelectionEndLineNumber(), endPosition.line + 1);
+    }
+  }
+
+  @Override
+  public Object getData(String dataId) {
+    return PlatformDataKeys.EDITOR.is(dataId) ? myEditor : super.getData(dataId);
+  }
+
+  protected VirtualFile getVirtualFile(@NonNls String filePath) {
+    String fullPath = getTestDataPath() + filePath;
+
+    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/'));
+    assertNotNull("file " + fullPath + " not found", vFile);
+    return vFile;
+  }
+
+  protected String getTestRoot(){
+    return FileUtil.toSystemIndependentName(getTestDataPath());
+  }
+
+  public Editor getEditor() {
+    return myEditor;
+  }
+
+  protected void type(char c) {
+    type(c, getEditor());
+  }
+
+  protected static void type(char c, Editor editor) {
+    EditorActionManager actionManager = EditorActionManager.getInstance();
+    DataContext dataContext = DataManager.getInstance().getDataContext();
+    if (c == '\n') {
+      actionManager.getActionHandler(IdeActions.ACTION_EDITOR_ENTER).execute(editor, dataContext);
+      return;
+    }
+    TypedAction action = actionManager.getTypedAction();
+    action.actionPerformed(editor, c, dataContext);
+  }
+
+  protected void caretRight() {
+    EditorActionManager actionManager = EditorActionManager.getInstance();
+    EditorActionHandler action = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT);
+    action.execute(getEditor(), DataManager.getInstance().getDataContext());
+  }
+  protected void caretUp() {
+    EditorActionManager actionManager = EditorActionManager.getInstance();
+    EditorActionHandler action = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_UP);
+    action.execute(getEditor(), DataManager.getInstance().getDataContext());
+  }
+  protected void deleteLine() {
+    EditorActionManager actionManager = EditorActionManager.getInstance();
+    EditorActionHandler action = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_DELETE_LINE);
+    action.execute(getEditor(), DataManager.getInstance().getDataContext());
+  }
+
+  protected void type(@NonNls String s) {
+    for (char c : s.toCharArray()) {
+      type(c);
+    }
+  }
+
+  protected void undo() {
+    UndoManager undoManager = UndoManager.getInstance(myProject);
+    TextEditor textEditor = TextEditorProvider.getInstance().getTextEditor(getEditor());
+    undoManager.undo(textEditor);
+  }
+
+  protected void backspace() {
+    backspace(getEditor());
+  }
+  protected void backspace(final Editor editor) {
+    CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
+      @Override
+      public void run() {
+        EditorActionManager actionManager = EditorActionManager.getInstance();
+        EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_BACKSPACE);
+
+        actionHandler.execute(editor, DataManager.getInstance().getDataContext());
+      }
+    }, "backspace", editor.getDocument());
+  }
+
+  protected void ctrlShiftF7() {
+    HighlightUsagesHandler.invoke(getProject(), getEditor(), getFile());
+  }
+
+  public static void ctrlW() {
+    AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET);
+    DataContext dataContext = DataManager.getInstance().getDataContext();
+    AnActionEvent event = new AnActionEvent(null, dataContext, "", action.getTemplatePresentation(), ActionManager.getInstance(), 0);
+    event.setInjectedContext(true);
+    action.actionPerformed(event);
+  }
+
+  public static void ctrlD() {
+    AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_DUPLICATE);
+    DataContext dataContext = DataManager.getInstance().getDataContext();
+    AnActionEvent event = new AnActionEvent(null, dataContext, "", action.getTemplatePresentation(), ActionManager.getInstance(), 0);
+    event.setInjectedContext(true);
+    action.actionPerformed(event);
+  }
+
+  @NotNull
+  protected PsiClass findClass(@NotNull @NonNls final String name) {
+    final PsiClass aClass = myJavaFacade.findClass(name, ProjectScope.getProjectScope(getProject()));
+    assertNotNull("Class " + name + " not found", aClass);
+    return aClass;
+  }
+
+  @NotNull
+  protected PsiPackage findPackage(@NotNull @NonNls final String name) {
+    final PsiPackage aPackage = myJavaFacade.findPackage(name);
+    assertNotNull("Package " + name + " not found", aPackage);
+    return aPackage;
+  }
+
+  protected void delete(@NotNull final Editor editor) {
+    CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
+      @Override
+      public void run() {
+        EditorActionManager actionManager = EditorActionManager.getInstance();
+        EditorActionHandler actionHandler = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_DELETE);
+
+        actionHandler.execute(editor, DataManager.getInstance().getDataContext());
+      }
+    }, "delete", editor.getDocument());
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestData.java b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestData.java
new file mode 100644
index 0000000..202db1b
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestData.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight;
+
+import com.intellij.testFramework.PsiTestData;
+
+/**
+ * @author Mike
+ */
+public class CodeInsightTestData extends PsiTestData{
+  public int LINE_NUMBER = -1;
+  public int COLUMN_NUMBER = -1;
+  public int SELECTION_START_LINE_NUMBER = -1;
+  public int SELECTION_START_COLUMN_NUMBER = -1;
+  public int SELECTION_END_LINE_NUMBER = -1;
+  public int SELECTION_END_COLUMN_NUMBER = -1;
+
+  public CodeInsightTestData() {
+  }
+
+  public int getLineNumber() {
+    return LINE_NUMBER;
+  }
+
+  public int getColumnNumber() {
+    return COLUMN_NUMBER;
+  }
+
+  public int getSelectionStartLineNumber() {
+    return SELECTION_START_LINE_NUMBER;
+  }
+
+  public int getSelectionStartColumnNumber() {
+    return SELECTION_START_COLUMN_NUMBER;
+  }
+
+  public int getSelectionEndLineNumber() {
+    return SELECTION_END_LINE_NUMBER;
+  }
+
+  public int getSelectionEndColumnNumber() {
+    return SELECTION_END_COLUMN_NUMBER;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/EditorInfo.java b/java/testFramework/src/com/intellij/codeInsight/EditorInfo.java
new file mode 100644
index 0000000..d770d7e
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/EditorInfo.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * @author cdr
+ */
+public class EditorInfo {
+  @NonNls public static final String CARET_MARKER = "<caret>";
+  @NonNls public static final String SELECTION_START_MARKER = "<selection>";
+  @NonNls public static final String SELECTION_END_MARKER = "</selection>";
+
+  String newFileText = null;
+  public RangeMarker caretMarker = null;
+  RangeMarker selStartMarker = null;
+  RangeMarker selEndMarker = null;
+
+  public EditorInfo(final String fileText) {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        updateCaretAndSelection(EditorFactory.getInstance().createDocument(fileText));
+      }
+    });
+  }
+
+  private boolean updateCaretAndSelection(final Document document) {
+    newFileText = document.getText();
+
+    int caretIndex = newFileText.indexOf(CARET_MARKER);
+    int selStartIndex = newFileText.indexOf(SELECTION_START_MARKER);
+    int selEndIndex = newFileText.indexOf(SELECTION_END_MARKER);
+
+    caretMarker = caretIndex >= 0 ? document.createRangeMarker(caretIndex, caretIndex) : null;
+    selStartMarker = selStartIndex >= 0 ? document.createRangeMarker(selStartIndex, selStartIndex) : null;
+    selEndMarker = selEndIndex >= 0 ? document.createRangeMarker(selEndIndex, selEndIndex) : null;
+
+    if (caretMarker != null) {
+      document.deleteString(caretMarker.getStartOffset(), caretMarker.getStartOffset() + CARET_MARKER.length());
+    }
+    if (selStartMarker != null) {
+      document.deleteString(selStartMarker.getStartOffset(), selStartMarker.getStartOffset() + SELECTION_START_MARKER.length());
+    }
+    if (selEndMarker != null) {
+      document.deleteString(selEndMarker.getStartOffset(), selEndMarker.getStartOffset() + SELECTION_END_MARKER.length());
+    }
+
+    newFileText = document.getText();
+    return caretMarker != null || selStartMarker != null || selEndMarker != null;
+  }
+
+  public String getNewFileText() {
+    return newFileText;
+  }
+
+  public void applyToEditor(Editor editor) {
+    if (caretMarker != null) {
+      int caretLine = StringUtil.offsetToLineNumber(newFileText, caretMarker.getStartOffset());
+      int caretCol = caretMarker.getStartOffset() - StringUtil.lineColToOffset(newFileText, caretLine, 0);
+      LogicalPosition pos = new LogicalPosition(caretLine, caretCol);
+      editor.getCaretModel().moveToLogicalPosition(pos);
+    }
+
+    if (selStartMarker != null) {
+      editor.getSelectionModel().setSelection(selStartMarker.getStartOffset(), selEndMarker.getStartOffset());
+    }
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy
new file mode 100644
index 0000000..9a05e8d
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionAutoPopupTestCase.groovy
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.completion
+
+import com.intellij.codeInsight.lookup.LookupManager
+import com.intellij.codeInsight.lookup.impl.LookupImpl
+import com.intellij.testFramework.fixtures.CompletionAutoPopupTester
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
+/**
+ * @author peter
+ */
+abstract class CompletionAutoPopupTestCase extends LightCodeInsightFixtureTestCase {
+  protected CompletionAutoPopupTester myTester
+
+  @Override protected void setUp() {
+    super.setUp()
+    myTester = new CompletionAutoPopupTester(myFixture)
+  }
+
+  void type(String s) {
+    myTester.typeWithPauses(s)
+  }
+
+  @Override protected boolean runInDispatchThread() {
+    return false;
+  }
+
+  @Override protected void invokeTestRunnable(Runnable runnable) {
+    myTester.runWithAutoPopupEnabled(runnable)
+  }
+
+  LookupImpl getLookup() {
+    (LookupImpl)LookupManager.getActiveLookup(myFixture.getEditor())
+  }
+
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java
new file mode 100644
index 0000000..714408d
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/completion/CompletionTestCase.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.completion;
+
+import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupManager;
+import com.intellij.codeInsight.lookup.impl.LookupImpl;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author mike
+ */
+@PlatformTestCase.WrapInCommand
+public abstract class CompletionTestCase extends DaemonAnalyzerTestCase {
+  protected String myPrefix;
+  protected LookupElement[] myItems;
+  private CompletionType myType = CompletionType.BASIC;
+
+  @Override
+  protected void tearDown() throws Exception {
+    try {
+      LookupManager.getInstance(myProject).hideActiveLookup();
+    }
+    finally {
+      super.tearDown();
+    }
+    myItems = null;
+  }
+
+  @Override
+  protected void configureByFile(String filePath) throws Exception {
+    super.configureByFile(filePath);
+
+    complete();
+  }
+
+  protected void configureByFileNoCompletion(String filePath) throws Exception {
+    super.configureByFile(filePath);
+  }
+
+  protected void complete() {
+    complete(1);
+  }
+
+  protected void complete(final int time) {
+    new CodeCompletionHandlerBase(myType).invokeCompletion(myProject, myEditor, time);
+
+    LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor);
+    myItems = lookup == null ? null : lookup.getItems().toArray(new LookupElement[lookup.getItems().size()]);
+    myPrefix = lookup == null ? "" : lookup.itemPattern(lookup.getItems().get(0));
+  }
+
+  public void setType(CompletionType type) {
+    myType = type;
+  }
+
+  protected void selectItem(LookupElement item, char ch) {
+    final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(myProject).getActiveLookup();
+    assert lookup != null;
+    lookup.setCurrentItem(item);
+    lookup.finishLookup(ch);
+  }
+
+  protected void selectItem(LookupElement item) {
+    selectItem(item, (char)0);
+  }
+
+  protected void doTestByCount(int finalCount, String... values) {
+    int index = 0;
+    if (myItems == null) {
+      assertEquals(0, finalCount);
+      return;
+    }
+    for (final LookupElement myItem : myItems) {
+      for (String value : values) {
+        if (value == null) {
+          assertFalse("Unacceptable value reached", true);
+        }
+        if (value.equals(myItem.getLookupString())) {
+          index++;
+          break;
+        }
+      }
+    }
+    assertEquals(Arrays.toString(myItems), finalCount, index);
+  }
+
+  @Nullable
+  protected LookupImpl getActiveLookup() {
+    return (LookupImpl)LookupManager.getActiveLookup(myEditor);
+  }
+
+  protected void assertStringItems(String... strings) {
+    assertNotNull(myItems);
+    List<String> actual = ContainerUtil.map(myItems, new Function<LookupElement, String>() {
+      @Override
+      public String fun(LookupElement element) {
+        return element.getLookupString();
+      }
+    });
+    assertOrderedEquals(actual, strings);
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java
new file mode 100644
index 0000000..5f435b0
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/completion/LightCompletionTestCase.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.completion;
+
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupManager;
+import com.intellij.codeInsight.lookup.impl.LookupImpl;
+import com.intellij.testFramework.LightCodeInsightTestCase;
+import com.intellij.util.containers.HashSet;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * @author mike
+ */
+public abstract class LightCompletionTestCase extends LightCodeInsightTestCase {
+  protected String myPrefix;
+  protected LookupElement[] myItems;
+  private CompletionType myType = CompletionType.BASIC;
+
+  @Override
+  protected void tearDown() throws Exception {
+    LookupManager.getInstance(getProject()).hideActiveLookup();
+    super.tearDown();
+  }
+
+  @Override
+  protected void configureByFile(@NotNull String filePath) {
+    super.configureByFile(filePath);
+
+    complete();
+  }
+
+  protected void configureByFileNoComplete(String filePath) throws Exception {
+    super.configureByFile(filePath);
+  }
+
+  protected void complete() {
+    complete(1);
+  }
+
+  protected void complete(final int time) {
+    new CodeCompletionHandlerBase(myType).invokeCompletion(getProject(), getEditor(), time);
+
+    LookupImpl lookup = (LookupImpl)LookupManager.getActiveLookup(myEditor);
+    myItems = lookup == null ? null : lookup.getItems().toArray(LookupElement.EMPTY_ARRAY);
+    myPrefix = lookup == null ? null : lookup.itemPattern(lookup.getItems().get(0));
+  }
+
+  public void setType(CompletionType type) {
+    myType = type;
+  }
+
+  protected void selectItem(LookupElement item) {
+    selectItem(item, (char)0);
+  }
+  
+  protected void selectItem(LookupElement item, char completionChar) {
+    final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(getProject()).getActiveLookup();
+    lookup.setCurrentItem(item);
+    if (completionChar == 0 || completionChar == '\n' || completionChar == '\t') {
+      lookup.finishLookup(completionChar);
+    } else {
+      type(completionChar);
+    }
+  }
+
+  protected void testByCount(int finalCount, @NonNls String... values) {
+    if (myItems == null) {
+      assertEquals(finalCount, 0);
+      return;
+    }
+    int index = 0;
+    for (final LookupElement myItem : myItems) {
+      for (String value : values) {
+        if (value == null) {
+          assertFalse("Unacceptable value reached: " + myItem.getLookupString(), true);
+        }
+        if (value.equals(myItem.getLookupString())) {
+          index++;
+          break;
+        }
+      }
+    }
+    assertEquals(finalCount, index);
+  }
+
+  protected void assertStringItems(@NonNls String... items) {
+    assertOrderedEquals(getLookupStrings(new ArrayList<String>()), items);
+  }
+
+  protected void assertContainsItems(final String... expected) {
+    final Set<String> actual = getLookupStrings(new HashSet<String>());
+    for (String s : expected) {
+      assertTrue("Expected '" + s + "' not found in " + actual,
+                 actual.contains(s));
+    }
+  }
+
+  protected void assertNotContainItems(final String... unexpected) {
+    final Set<String> actual = getLookupStrings(new HashSet<String>());
+    for (String s : unexpected) {
+      assertFalse("Unexpected '" + s + "' presented in " + actual,
+                  actual.contains(s));
+    }
+  }
+
+  private <T extends Collection<String>> T getLookupStrings(T actual) {
+    if (myItems != null) {
+      for (LookupElement lookupElement : myItems) {
+        actual.add(lookupElement.getLookupString());
+      }
+    }
+    return actual;
+  }
+
+  protected static LookupImpl getLookup() {
+    return (LookupImpl)LookupManager.getActiveLookup(myEditor);
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java
new file mode 100644
index 0000000..ae80acc
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/DaemonAnalyzerTestCase.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon;
+
+import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeHighlighting.Pass;
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.IntentionManager;
+import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.intellij.codeInspection.InspectionToolProvider;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ModifiableModel;
+import com.intellij.codeInspection.ex.*;
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.ide.startup.StartupManagerEx;
+import com.intellij.ide.startup.impl.StartupManagerImpl;
+import com.intellij.lang.ExternalAnnotatorsFilter;
+import com.intellij.lang.LanguageAnnotators;
+import com.intellij.lang.StdLanguages;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.DumbService;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.*;
+import com.intellij.profile.codeInspection.InspectionProfileManager;
+import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+import com.intellij.psi.impl.cache.CacheManager;
+import com.intellij.psi.impl.search.IndexPatternBuilder;
+import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
+import com.intellij.psi.impl.source.tree.TreeElement;
+import com.intellij.psi.impl.source.tree.TreeUtil;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.UsageSearchContext;
+import com.intellij.psi.xml.XmlFileNSInfoProvider;
+import com.intellij.testFramework.ExpectedHighlightingData;
+import com.intellij.testFramework.FileTreeAccessFilter;
+import com.intellij.testFramework.HighlightTestInfo;
+import com.intellij.testFramework.LightPlatformTestCase;
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.xml.XmlSchemaProvider;
+import gnu.trove.THashMap;
+import gnu.trove.TIntArrayList;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
+  private final Map<String, InspectionToolWrapper> myAvailableTools = new THashMap<String, InspectionToolWrapper>();
+  private final FileTreeAccessFilter myFileTreeAccessFilter = new FileTreeAccessFilter();
+
+  @Override
+  protected boolean isRunInWriteAction() {
+    return false;
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    final LocalInspectionTool[] tools = configureLocalInspectionTools();
+    for (LocalInspectionTool tool : tools) {
+      enableInspectionTool(tool);
+    }
+
+    final InspectionProfileImpl profile = new InspectionProfileImpl(LightPlatformTestCase.PROFILE) {
+      @Override
+      @NotNull
+      public ModifiableModel getModifiableModel() {
+        mySource = this;
+        return this;
+      }
+
+      @Override
+      @NotNull
+      public InspectionTool[] getInspectionTools(PsiElement element) {
+        Collection<InspectionToolWrapper> values = myAvailableTools.values();
+        return values.toArray(new InspectionTool[values.size()]);
+      }
+
+      @Override
+      public List<ToolsImpl> getAllEnabledInspectionTools(Project project) {
+        List<ToolsImpl> result = new ArrayList<ToolsImpl>();
+        for (InspectionProfileEntry entry : getInspectionTools(null)) {
+          result.add(new ToolsImpl(entry, entry.getDefaultLevel(), true));
+        }
+        return result;
+      }
+
+      @Override
+      public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) {
+        return key != null && myAvailableTools.containsKey(key.toString());
+      }
+
+      @Override
+      public HighlightDisplayLevel getErrorLevel(@NotNull HighlightDisplayKey key, PsiElement element) {
+        final InspectionProfileEntry localInspectionTool = myAvailableTools.get(key.toString());
+        return localInspectionTool != null ? localInspectionTool.getDefaultLevel() : HighlightDisplayLevel.WARNING;
+      }
+
+      @Override
+      public InspectionTool getInspectionTool(@NotNull String shortName, @NotNull PsiElement element) {
+        return myAvailableTools.get(shortName);
+      }
+    };
+    final InspectionProfileManager inspectionProfileManager = InspectionProfileManager.getInstance();
+    inspectionProfileManager.addProfile(profile);
+    inspectionProfileManager.setRootProfile(LightPlatformTestCase.PROFILE);
+    Disposer.register(getProject(), new Disposable() {
+      @Override
+      public void dispose() {
+        inspectionProfileManager.deleteProfile(LightPlatformTestCase.PROFILE);
+      }
+    });
+    InspectionProjectProfileManager.getInstance(getProject()).updateProfile(profile);
+    InspectionProjectProfileManager.getInstance(getProject()).setProjectProfile(profile.getName());
+    DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject());
+    daemonCodeAnalyzer.prepareForTest();
+    final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject());
+    startupManager.runStartupActivities();
+    startupManager.startCacheUpdate();
+    startupManager.runPostStartupActivities();
+    DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
+
+    if (isPerformanceTest()) {
+      IntentionManager.getInstance().getAvailableIntentionActions();  // hack to avoid slowdowns in PyExtensionFactory
+      PathManagerEx.getTestDataPath(); // to cache stuff
+      ReferenceProvidersRegistry.getInstance(); // pre-load tons of classes
+      InjectedLanguageManager.getInstance(getProject()); // zillion of Dom Sem classes
+      LanguageAnnotators.INSTANCE.allForLanguage(JavaLanguage.INSTANCE); // pile of annotator classes loads
+      LanguageAnnotators.INSTANCE.allForLanguage(StdLanguages.XML);
+      ProblemHighlightFilter.EP_NAME.getExtensions();
+      Extensions.getExtensions(ImplicitUsageProvider.EP_NAME);
+      Extensions.getExtensions(XmlSchemaProvider.EP_NAME);
+      Extensions.getExtensions(XmlFileNSInfoProvider.EP_NAME);
+      Extensions.getExtensions(ExternalAnnotatorsFilter.EXTENSION_POINT_NAME);
+      Extensions.getExtensions(IndexPatternBuilder.EP_NAME);
+    }
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    ((StartupManagerImpl)StartupManager.getInstance(getProject())).checkCleared();
+    ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).cleanupAfterTest(!LightPlatformTestCase.isLight(getProject()));
+    super.tearDown();
+    //((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).assertPointersDisposed();
+  }
+
+  protected void enableInspectionTool(InspectionProfileEntry tool){
+    InspectionToolWrapper wrapper = InspectionToolRegistrar.wrapTool(tool);
+    final String shortName = wrapper.getShortName();
+    final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
+    if (key == null) {
+      HighlightDisplayKey.register(shortName, wrapper.getDisplayName(), ((LocalInspectionToolWrapper)wrapper).getID());
+    }
+    myAvailableTools.put(shortName, wrapper);
+  }
+
+  protected void enableInspectionToolsFromProvider(InspectionToolProvider toolProvider){
+    try {
+      for(Class c:toolProvider.getInspectionClasses()) {
+        enableInspectionTool((LocalInspectionTool)c.newInstance());
+      }
+    }
+    catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  protected void disableInspectionTool(String shortName){
+    myAvailableTools.remove(shortName);
+  }
+
+  protected LocalInspectionTool[] configureLocalInspectionTools() {
+    return LocalInspectionTool.EMPTY_ARRAY;
+  }
+
+  protected static LocalInspectionTool[] createLocalInspectionTools(final InspectionToolProvider... provider) {
+    final ArrayList<LocalInspectionTool> result = new ArrayList<LocalInspectionTool>();
+    for (InspectionToolProvider toolProvider : provider) {
+      for (Class aClass : toolProvider.getInspectionClasses()) {
+        try {
+          final Object tool = aClass.newInstance();
+          assertTrue(tool instanceof LocalInspectionTool);
+          result.add((LocalInspectionTool)tool);
+        }
+        catch (Exception e) {
+          LOG.error(e);
+        }
+      }
+    }
+    return result.toArray(new LocalInspectionTool[result.size()]);
+  }
+
+  protected void doTest(@NonNls @NotNull String filePath, boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) throws Exception {
+    configureByFile(filePath);
+    doDoTest(checkWarnings, checkInfos, checkWeakWarnings);
+  }
+
+  protected void doTest(@NonNls @NotNull String filePath, boolean checkWarnings, boolean checkInfos) throws Exception {
+    doTest(filePath, checkWarnings, checkInfos, false);
+  }
+
+  protected void doTest(@NonNls @NotNull String filePath, @NonNls String projectRoot, boolean checkWarnings, boolean checkInfos) throws Exception {
+    configureByFile(filePath, projectRoot);
+    doDoTest(checkWarnings, checkInfos);
+  }
+
+  @NotNull
+  @SuppressWarnings("TestMethodWithIncorrectSignature")
+  protected HighlightTestInfo testFile(@NonNls @NotNull String... filePath) {
+    return new HighlightTestInfo(getTestRootDisposable(), filePath){
+      @Override
+      public HighlightTestInfo doTest() throws Exception {
+        configureByFiles(projectRoot, filePaths);
+        ExpectedHighlightingData data = new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, myFile);
+        if (checkSymbolNames) data.checkSymbolNames();
+        checkHighlighting(data);
+        return this;
+      }
+    };
+  }
+
+  protected void doTest(@NotNull VirtualFile vFile, boolean checkWarnings, boolean checkInfos) throws Exception {
+    doTest(new VirtualFile[] { vFile }, checkWarnings, checkInfos );
+  }
+
+  protected void doTest(@NotNull VirtualFile[] vFile, boolean checkWarnings, boolean checkInfos) throws Exception {
+    configureByFiles(null, vFile);
+    doDoTest(checkWarnings, checkInfos);
+  }
+
+  protected void doTest(boolean checkWarnings, boolean checkInfos, String ... files) throws Exception {
+    configureByFiles(null, files);
+    doDoTest(checkWarnings, checkInfos);
+  }
+
+  @NotNull
+  protected Collection<HighlightInfo> doDoTest(boolean checkWarnings, boolean checkInfos) {
+    return doDoTest(checkWarnings, checkInfos, false);
+  }
+
+  protected Collection<HighlightInfo> doDoTest(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) {
+    return checkHighlighting(new ExpectedHighlightingData(myEditor.getDocument(),checkWarnings, checkWeakWarnings, checkInfos, myFile));
+  }
+
+  @NotNull
+  protected Collection<HighlightInfo> checkHighlighting(@NotNull final ExpectedHighlightingData data) {
+    data.init();
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    //to load text
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        TreeUtil.clearCaches((TreeElement)myFile.getNode());
+      }
+    });
+
+
+    //to initialize caches
+    if (!DumbService.isDumb(getProject())) {
+      CacheManager.SERVICE.getInstance(myProject).getFilesWithWord("XXX", UsageSearchContext.IN_COMMENTS, GlobalSearchScope.allScope(myProject), true);
+    }
+    final JavaPsiFacadeEx facade = getJavaFacade();
+    if (facade != null) {
+      facade.setAssertOnFileLoadingFilter(myFileTreeAccessFilter); // check repository work
+    }
+
+    Collection<HighlightInfo> infos = doHighlighting();
+
+    if (facade != null) {
+      facade.setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
+    }
+
+    String text = myEditor.getDocument().getText();
+    data.checkLineMarkers(DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(getFile()), getProject()), text);
+    data.checkResult(infos, text);
+    return infos;
+  }
+
+  public void allowTreeAccessForFile(@NotNull VirtualFile file) {
+    myFileTreeAccessFilter.allowTreeAccessForFile(file);
+  }
+
+  @NotNull
+  protected List<HighlightInfo> highlightErrors() {
+    return doHighlighting(HighlightSeverity.ERROR);
+  }
+
+  @NotNull
+  protected List<HighlightInfo> doHighlighting(@NotNull HighlightSeverity minSeverity) {
+    return filter(doHighlighting(), minSeverity);
+  }
+
+  @NotNull
+  protected List<HighlightInfo> doHighlighting() {
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    TIntArrayList toIgnore = new TIntArrayList();
+    if (!doTestLineMarkers()) {
+      toIgnore.add(Pass.UPDATE_OVERRIDEN_MARKERS);
+      toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
+      toIgnore.add(Pass.LINE_MARKERS);
+    }
+
+    if (!doExternalValidation()) {
+      toIgnore.add(Pass.EXTERNAL_TOOLS);
+    }
+    if (forceExternalValidation()) {
+      toIgnore.add(Pass.LINE_MARKERS);
+      toIgnore.add(Pass.LOCAL_INSPECTIONS);
+      toIgnore.add(Pass.POPUP_HINTS);
+      toIgnore.add(Pass.POST_UPDATE_ALL);
+      toIgnore.add(Pass.UPDATE_ALL);
+      toIgnore.add(Pass.UPDATE_OVERRIDEN_MARKERS);
+      toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
+    }
+
+    boolean canChange = canChangeDocumentDuringHighlighting();
+    List<HighlightInfo> infos = CodeInsightTestFixtureImpl.instantiateAndRun(getFile(), getEditor(), toIgnore.toNativeArray(), canChange);
+
+    if (!canChange) {
+      Document document = getDocument(getFile());
+      ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).getFileStatusMap().assertAllDirtyScopesAreNull(document);
+    }
+
+    return infos;
+  }
+
+  @Retention(RetentionPolicy.RUNTIME)
+  @Target({ElementType.METHOD, ElementType.TYPE})
+  public @interface CanChangeDocumentDuringHighlighting {}
+
+  private boolean canChangeDocumentDuringHighlighting() {
+    return annotatedWith(CanChangeDocumentDuringHighlighting.class);
+  }
+
+  @NotNull
+  public static List<HighlightInfo> filter(@NotNull List<HighlightInfo> infos, @NotNull HighlightSeverity minSeverity) {
+    ArrayList<HighlightInfo> result = new ArrayList<HighlightInfo>();
+    for (final HighlightInfo info : infos) {
+      if (info.getSeverity().compareTo(minSeverity) >= 0) result.add(info);
+    }
+    return result;
+  }
+
+  protected boolean doTestLineMarkers() {
+    return false;
+  }
+
+  protected boolean doExternalValidation() {
+    return true;
+  }
+
+  protected boolean forceExternalValidation() {
+    return false;
+  }
+
+  protected static void findAndInvokeIntentionAction(@NotNull Collection<HighlightInfo> infos, @NotNull String intentionActionName, @NotNull Editor editor,
+                                                     @NotNull PsiFile file) throws IncorrectOperationException {
+    IntentionAction intentionAction = findIntentionAction(infos, intentionActionName, editor, file);
+
+    assertNotNull(intentionActionName, intentionAction);
+    assertTrue(ShowIntentionActionsHandler.chooseActionAndInvoke(file, editor, intentionAction, intentionActionName));
+  }
+
+  protected static IntentionAction findIntentionAction(@NotNull Collection<HighlightInfo> infos, @NotNull String intentionActionName, @NotNull Editor editor,
+                                                       @NotNull PsiFile file) {
+    List<IntentionAction> actions = LightQuickFixTestCase.getAvailableActions(editor, file);
+    IntentionAction intentionAction = LightQuickFixTestCase.findActionWithText(actions, intentionActionName);
+
+    if (intentionAction == null) {
+      final List<IntentionAction> availableActions = new ArrayList<IntentionAction>();
+
+      for (HighlightInfo info :infos) {
+        if (info.quickFixActionRanges != null) {
+          for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
+            IntentionAction action = pair.first.getAction();
+            if (action.isAvailable(file.getProject(), editor, file)) availableActions.add(action);
+          }
+        }
+      }
+
+      intentionAction = LightQuickFixTestCase.findActionWithText(
+        availableActions,
+        intentionActionName
+      );
+    }
+    return intentionAction;
+  }
+
+  public void checkHighlighting(Editor editor, boolean checkWarnings, boolean checkInfos) {
+    setActiveEditor(editor);
+    doDoTest(checkWarnings, checkInfos);
+  }
+
+  public PsiClass createClass(String text) throws IOException {
+    return createClass(myModule, text);
+  }
+
+  protected PsiClass createClass(final Module module, final String text) throws IOException {
+    return new WriteCommandAction<PsiClass>(getProject()) {
+      @Override
+      protected void run(Result<PsiClass> result) throws Throwable {
+        final PsiFileFactory factory = PsiFileFactory.getInstance(getProject());
+        final PsiJavaFile javaFile = (PsiJavaFile)factory.createFileFromText("a.java", JavaFileType.INSTANCE, text);
+        final String qname = javaFile.getClasses()[0].getQualifiedName();
+        assertNotNull(qname);
+        final VirtualFile[] files = ModuleRootManager.getInstance(module).getSourceRoots();
+        File dir;
+        if (files.length > 0) {
+          dir = VfsUtilCore.virtualToIoFile(files[0]);
+        }
+        else {
+          dir = createTempDirectory();
+          VirtualFile vDir =
+            LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/'));
+          addSourceContentToRoots(module, vDir);
+        }
+
+        File file = new File(dir, qname.replace('.', '/') + ".java");
+        FileUtil.createIfDoesntExist(file);
+        VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(file.getCanonicalPath().replace(File.separatorChar, '/'));
+        assertNotNull(vFile);
+        VfsUtil.saveText(vFile, text);
+        PsiJavaFile psiFile = (PsiJavaFile)myPsiManager.findFile(vFile);
+        assertNotNull(psiFile);
+        PsiClass psiClass = psiFile.getClasses()[0];
+        result.setResult(psiClass);
+
+      }
+    }.execute().throwException().getResultObject();
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java
new file mode 100644
index 0000000..2cc216d
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon;
+
+import com.intellij.codeHighlighting.Pass;
+import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.injected.editor.EditorWindow;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.testFramework.ExpectedHighlightingData;
+import com.intellij.testFramework.FileTreeAccessFilter;
+import com.intellij.testFramework.HighlightTestInfo;
+import com.intellij.testFramework.LightCodeInsightTestCase;
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+
+public abstract class LightDaemonAnalyzerTestCase extends LightCodeInsightTestCase {
+  private final FileTreeAccessFilter myJavaFilesFilter = new FileTreeAccessFilter();
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).prepareForTest();
+    DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).cleanupAfterTest(!isLight(getProject()));
+    super.tearDown();
+  }
+
+  @Override
+  protected void runTest() throws Throwable {
+    final Throwable[] throwable = {null};
+    CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
+      @Override
+      public void run() {
+        try {
+          doRunTest();
+        }
+        catch (Throwable t) {
+          throwable[0] = t;
+        }
+      }
+    }, "", null);
+    if (throwable[0] != null) {
+      throw throwable[0];
+    }
+  }
+
+  protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkInfos) {
+    configureByFile(filePath);
+    doTestConfiguredFile(checkWarnings, checkInfos, filePath);
+  }
+
+  protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos) {
+    configureByFile(filePath);
+    doTestConfiguredFile(checkWarnings, checkWeakWarnings, checkInfos, filePath);
+  }
+
+  protected void doTestConfiguredFile(boolean checkWarnings, boolean checkInfos, @Nullable String filePath) {
+    doTestConfiguredFile(checkWarnings, false, checkInfos, filePath);
+  }
+
+  protected void doTestConfiguredFile(boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos, @Nullable String filePath) {
+    getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
+
+    ExpectedHighlightingData data = new ExpectedHighlightingData(getEditor().getDocument(), checkWarnings, checkWeakWarnings, checkInfos);
+    checkHighlighting(data, composeLocalPath(filePath));
+  }
+
+  @Nullable
+  private String composeLocalPath(@Nullable String filePath) {
+    return filePath != null ? getTestDataPath() + "/" + filePath : null;
+  }
+
+  private void checkHighlighting(ExpectedHighlightingData data, String filePath) {
+    data.init();
+
+    PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+    getFile().getText(); //to load text
+    myJavaFilesFilter.allowTreeAccessForFile(getVFile());
+    getJavaFacade().setAssertOnFileLoadingFilter(myJavaFilesFilter); // check repository work
+
+    Collection<HighlightInfo> infos = doHighlighting();
+
+    getJavaFacade().setAssertOnFileLoadingFilter(VirtualFileFilter.NONE);
+
+    data.checkResult(infos, getEditor().getDocument().getText(), filePath);
+  }
+
+  protected HighlightTestInfo doTestFile(@NonNls @NotNull String filePath) {
+    return new HighlightTestInfo(getTestRootDisposable(), filePath){
+      @Override
+      public HighlightTestInfo doTest() throws Exception {
+        String path = assertOneElement(filePaths);
+        configureByFile(path);
+        ExpectedHighlightingData data = new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, myFile);
+        if (checkSymbolNames) data.checkSymbolNames();
+
+        checkHighlighting(data, composeLocalPath(path));
+        return this;
+      }
+    };
+  }
+
+  @NotNull
+  protected List<HighlightInfo> highlightErrors() {
+    return doHighlighting(HighlightSeverity.ERROR);
+  }
+
+  @NotNull
+  protected List<HighlightInfo> doHighlighting() {
+    PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+
+    int[] toIgnore = doFolding() ? ArrayUtil.EMPTY_INT_ARRAY : new int[]{Pass.UPDATE_FOLDING};
+    Editor editor = getEditor();
+    PsiFile file = getFile();
+    if (editor instanceof EditorWindow) {
+      editor = ((EditorWindow)editor).getDelegate();
+      file = InjectedLanguageUtil.getTopLevelFile(file);
+    }
+    
+    return CodeInsightTestFixtureImpl.instantiateAndRun(file, editor, toIgnore, false);
+  }
+
+  protected List<HighlightInfo> doHighlighting(HighlightSeverity minSeverity) {
+    return DaemonAnalyzerTestCase.filter(doHighlighting(), minSeverity);
+  }
+
+  protected boolean doFolding() {
+    return false;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/LightIntentionActionTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/LightIntentionActionTestCase.java
new file mode 100644
index 0000000..9268189
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/LightIntentionActionTestCase.java
@@ -0,0 +1,6 @@
+package com.intellij.codeInsight.daemon;
+
+import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase;
+
+public abstract class LightIntentionActionTestCase extends LightQuickFixTestCase {
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java
new file mode 100644
index 0000000..9cf1c20
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/LightQuickFixTestCase.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.quickFix;
+
+import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
+import com.intellij.lang.Commenter;
+import com.intellij.lang.LanguageCommenters;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.rt.execution.junit.FileComparisonFailure;
+import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
+import com.intellij.testFramework.LightPlatformTestCase;
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.ui.UIUtil;
+import org.intellij.lang.annotations.RegExp;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public abstract class LightQuickFixTestCase extends LightDaemonAnalyzerTestCase {
+  @NonNls private static final String BEFORE_PREFIX = "before";
+  private static QuickFixTestCase myWrapper;
+
+  protected boolean shouldBeAvailableAfterExecution() {
+    return false;
+  }
+
+  protected Pair<String, Boolean> parseActionHintImpl(final PsiFile file, String contents) {
+    return parseActionHint(file, contents);
+  }
+
+  private static void doTestFor(final String testName, final QuickFixTestCase quickFixTestCase) {
+    final String relativePath = quickFixTestCase.getBasePath() + "/" + BEFORE_PREFIX + testName;
+    final String testFullPath = quickFixTestCase.getTestDataPath().replace(File.separatorChar, '/') + relativePath;
+    final File testFile = new File(testFullPath);
+    CommandProcessor.getInstance().executeCommand(quickFixTestCase.getProject(), new Runnable() {
+      @Override
+      public void run() {
+        try {
+          String contents = StringUtil.convertLineSeparators(FileUtil.loadFile(testFile, CharsetToolkit.UTF8));
+          quickFixTestCase.configureFromFileText(testFile.getName(), contents);
+          quickFixTestCase.bringRealEditorBack();
+          final Pair<String, Boolean> pair = quickFixTestCase.parseActionHintImpl(quickFixTestCase.getFile(), contents);
+          final String text = pair.getFirst();
+          final boolean actionShouldBeAvailable = pair.getSecond().booleanValue();
+
+          quickFixTestCase.beforeActionStarted(testName, contents);
+
+          try {
+            myWrapper = quickFixTestCase;
+            quickFixTestCase.doAction(text, actionShouldBeAvailable, testFullPath, testName);
+          }
+          finally {
+            myWrapper = null;
+            quickFixTestCase.afterActionCompleted(testName, contents);
+          }
+        }
+        catch (FileComparisonFailure e){
+          throw e;
+        }
+        catch (Throwable e) {
+          e.printStackTrace();
+          fail(testName);
+        }
+      }
+    }, "", "");
+  }
+
+  protected void afterActionCompleted(final String testName, final String contents) {
+  }
+
+  protected void beforeActionStarted(final String testName, final String contents) {
+  }
+
+  public static Pair<String, Boolean> parseActionHint(final PsiFile file, String contents) {
+    return parseActionHint(file, contents, " \"(.*)\" \"(true|false)\".*");
+  }
+
+  public static Pair<String, Boolean> parseActionHint(final PsiFile file, String contents, @NonNls @RegExp String actionPattern) {
+    PsiFile hostFile = InjectedLanguageUtil.getTopLevelFile(file);
+
+    final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(hostFile.getLanguage());
+    String comment = commenter.getLineCommentPrefix();
+    if (comment == null) {
+      comment = commenter.getBlockCommentPrefix();
+    }
+    
+    // "quick fix action text to perform" "should be available"
+    Pattern pattern = Pattern.compile("^" + comment.replace("*", "\\*") + actionPattern, Pattern.DOTALL);
+    Matcher matcher = pattern.matcher(contents);
+    assertTrue("No comment found in "+file.getVirtualFile(), matcher.matches());
+    final String text = matcher.group(1);
+    final Boolean actionShouldBeAvailable = Boolean.valueOf(matcher.group(2));
+    return Pair.create(text, actionShouldBeAvailable);
+  }
+
+  @SuppressWarnings({"HardCodedStringLiteral"})
+  public static void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath, final String testName,
+                              QuickFixTestCase quickFix)
+    throws Exception {
+    IntentionAction action = quickFix.findActionWithText(text);
+    if (action == null) {
+      if (actionShouldBeAvailable) {
+        List<IntentionAction> actions = quickFix.getAvailableActions();
+        List<String> texts = new ArrayList<String>();
+        for (IntentionAction intentionAction : actions) {
+          texts.add(intentionAction.getText());
+        }
+        Collection<HighlightInfo> infos = quickFix.doHighlighting();
+        fail("Action with text '" + text + "' is not available in test " + testFullPath+"\nAvailable actions ("+texts.size()+"): "+texts+"\n"+actions+"\nInfos:"+infos);
+      }
+    }
+    else {
+      if (!actionShouldBeAvailable) {
+        fail("Action '" + text + "' is available (but must not) in test " + testFullPath);
+      }
+      quickFix.invoke(action);
+      UIUtil.dispatchAllInvocationEvents();
+      UIUtil.dispatchAllInvocationEvents();
+      if (!quickFix.shouldBeAvailableAfterExecution()) {
+        final IntentionAction afterAction = quickFix.findActionWithText(text);
+        if (afterAction != null) {
+          fail("Action '" + text + "' is still available after its invocation in test " + testFullPath);
+        }
+      }
+      final String expectedFilePath = quickFix.getBasePath() + "/after" + testName;
+      quickFix.checkResultByFile("In file :" + expectedFilePath, expectedFilePath, false);
+    }
+  }
+
+  protected void doAction(final String text, final boolean actionShouldBeAvailable, final String testFullPath, final String testName)
+    throws Exception {
+    doAction(text, actionShouldBeAvailable, testFullPath, testName, myWrapper);
+  }
+
+  protected void doAction(final String actionName) {
+    final List<IntentionAction> available = getAvailableActions();
+    final IntentionAction action = findActionWithText(available, actionName);
+    assertNotNull("Action '" + actionName + "' not found among " + available.toString(), action);
+    invoke(action);
+  }
+
+  protected static void invoke(IntentionAction action) throws IncorrectOperationException {
+    ShowIntentionActionsHandler.chooseActionAndInvoke(getFile(), getEditor(), action, action.getText());
+  }
+
+  protected IntentionAction findActionWithText(final String text) {
+    return findActionWithText(getAvailableActions(), text);
+  }
+
+  public static IntentionAction findActionWithText(final List<IntentionAction> actions, final String text) {
+    for (IntentionAction action : actions) {
+      if (text.equals(action.getText())) {
+        return action;
+      }
+    }
+    return null;
+  }
+
+  public static void doAllTests(QuickFixTestCase testCase) throws Exception {
+    assertNotNull("getBasePath() should not return null!", testCase.getBasePath());
+
+    final String testDirPath = testCase.getTestDataPath().replace(File.separatorChar, '/') + testCase.getBasePath();
+    File testDir = new File(testDirPath);
+    final File[] files = testDir.listFiles(new FilenameFilter() {
+      @Override
+      public boolean accept(File dir, @NonNls String name) {
+        return name.startsWith(BEFORE_PREFIX);
+      }
+    });
+
+    if (files == null) {
+      fail("Test files not found in " + testDirPath);
+    }
+
+    for (File file : files) {
+      final String testName = file.getName().substring(BEFORE_PREFIX.length());
+      doTestFor(testName, testCase);
+      System.out.println(file.getPath());
+    }
+    assertTrue("Test files not found in "+testDirPath,files.length != 0);
+  }
+
+  protected void doSingleTest(String fileSuffix) {
+    doTestFor(fileSuffix, createWrapper());
+  }
+
+  protected void doAllTests() throws Exception {
+    doAllTests(createWrapper());
+  }
+
+  private QuickFixTestCase createWrapper() {
+    return new QuickFixTestCase() {
+      @Override
+      public String getBasePath() {
+        return LightQuickFixTestCase.this.getBasePath();
+      }
+
+      @Override
+      public String getTestDataPath() {
+        return LightQuickFixTestCase.this.getTestDataPath();
+      }
+
+      @Override
+      public Pair<String, Boolean> parseActionHintImpl(PsiFile file, String contents) {
+        return LightQuickFixTestCase.this.parseActionHintImpl(file, contents);
+      }
+
+      @Override
+      public void beforeActionStarted(String testName, String contents) {
+        LightQuickFixTestCase.this.beforeActionStarted(testName, contents);
+      }
+
+      @Override
+      public void afterActionCompleted(String testName, String contents) {
+        LightQuickFixTestCase.this.afterActionCompleted(testName, contents);
+      }
+
+      @Override
+      public void doAction(String text, boolean actionShouldBeAvailable, String testFullPath, String testName) throws Exception {
+        LightQuickFixTestCase.this.doAction(text, actionShouldBeAvailable, testFullPath, testName);
+      }
+
+      @Override
+      public void checkResultByFile(String s, String expectedFilePath, boolean b) throws Exception {
+        LightQuickFixTestCase.this.checkResultByFile(s, expectedFilePath, b);
+      }
+
+      @Override
+      public IntentionAction findActionWithText(String text) {
+        return LightQuickFixTestCase.this.findActionWithText(text);
+      }
+
+      @Override
+      public boolean shouldBeAvailableAfterExecution() {
+        return LightQuickFixTestCase.this.shouldBeAvailableAfterExecution();
+      }
+
+      @Override
+      public void invoke(IntentionAction action) {
+        LightQuickFixTestCase.invoke(action);
+      }
+
+      @Override
+      public List<HighlightInfo> doHighlighting() {
+        return LightQuickFixTestCase.this.doHighlighting();
+      }
+
+      @Override
+      public List<IntentionAction> getAvailableActions() {
+        return LightQuickFixTestCase.this.getAvailableActions();
+      }
+
+      @Override
+      public void configureFromFileText(String name, String contents) throws IOException {
+        LightPlatformCodeInsightTestCase.configureFromFileText(name, contents);
+      }
+
+      @Override
+      public PsiFile getFile() {
+        return LightPlatformCodeInsightTestCase.getFile();
+      }
+
+      @Override
+      public Project getProject() {
+        return LightPlatformTestCase.getProject();
+      }
+
+      @Override
+      public void bringRealEditorBack() {
+        LightPlatformCodeInsightTestCase.bringRealEditorBack();
+      }
+    };
+  }
+
+  protected List<IntentionAction> getAvailableActions() {
+    doHighlighting();
+    return getAvailableActions(getEditor(), getFile());
+  }
+
+  public static List<IntentionAction> getAvailableActions(@NotNull Editor editor, @NotNull PsiFile file) {
+    return CodeInsightTestFixtureImpl.getAvailableIntentions(editor, file);
+  }
+
+  @NonNls protected String getBasePath() {return null;}
+}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java
new file mode 100644
index 0000000..6134887
--- /dev/null
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/QuickFixTestCase.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.quickFix;
+
+import com.intellij.codeInsight.daemon.impl.HighlightInfo;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiFile;
+
+import java.util.List;
+
+/**
+ * @author Maxim.Mossienko
+*         Date: 22.01.2009
+*         Time: 0:28:45
+*/
+public interface QuickFixTestCase {
+  String getBasePath();
+
+  String getTestDataPath();
+
+  Pair<String, Boolean> parseActionHintImpl(PsiFile file, String contents);
+
+  void beforeActionStarted(String testName, String contents);
+
+  void afterActionCompleted(String testName, String contents);
+
+  void doAction(String text, boolean actionShouldBeAvailable, String testFullPath, String testName) throws Exception;
+
+  void checkResultByFile(String s, String expectedFilePath, boolean b) throws Exception;
+
+  IntentionAction findActionWithText(String text);
+
+  boolean shouldBeAvailableAfterExecution();
+
+  void invoke(IntentionAction action);
+
+  List<HighlightInfo> doHighlighting();
+
+  List<IntentionAction> getAvailableActions();
+
+  void bringRealEditorBack();
+
+  void configureFromFileText(String name, String contents) throws Throwable;
+
+  PsiFile getFile();
+
+  Project getProject();
+}
diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java
new file mode 100644
index 0000000..6dcf778
--- /dev/null
+++ b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java
@@ -0,0 +1,190 @@
+package com.intellij.ide.projectWizard;
+
+import com.intellij.ide.actions.ImportModuleAction;
+import com.intellij.ide.impl.NewProjectUtil;
+import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
+import com.intellij.ide.util.newProjectWizard.SelectTemplateStep;
+import com.intellij.ide.util.projectWizard.ModuleWizardStep;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider;
+import com.intellij.openapi.roots.ui.configuration.actions.NewModuleAction;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.platform.ProjectTemplate;
+import com.intellij.projectImport.ProjectImportProvider;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.util.Consumer;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Dmitry Avdeev
+ *         Date: 10/29/12
+ */
+public abstract class ProjectWizardTestCase extends PlatformTestCase {
+
+  protected final List<Sdk> mySdks = new ArrayList<Sdk>();
+  protected AddModuleWizard myWizard;
+  @Nullable
+  private Project myCreatedProject;
+
+  protected Project createProjectFromTemplate(String group, String name, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException {
+    runWizard(group, name, null, adjuster);
+    try {
+      myCreatedProject = NewProjectUtil.createFromWizard(myWizard, null);
+    }
+    catch (Throwable e) {
+      myCreatedProject = ContainerUtil.find(myProjectManager.getOpenProjects(), new Condition<Project>() {
+        @Override
+        public boolean value(Project project) {
+          return myWizard.getProjectName().equals(project.getName());
+        }
+      });
+      throw new RuntimeException(e);
+    }
+    assertNotNull(myCreatedProject);
+    UIUtil.dispatchAllInvocationEvents();
+
+    Project[] projects = myProjectManager.getOpenProjects();
+    assertEquals(2, projects.length);
+    return myCreatedProject;
+  }
+
+  @Nullable
+  protected Module createModuleFromTemplate(String group, String name, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException {
+    runWizard(group, name, getProject(), adjuster);
+    return createModuleFromWizard();
+  }
+
+  protected Module createModuleFromWizard() {
+    return new NewModuleAction().createModuleFromWizard(myProject, null, myWizard);
+  }
+
+  protected void runWizard(String group, String name, Project project, @Nullable Consumer<ModuleWizardStep> adjuster) throws IOException {
+
+    createWizard(project);
+    SelectTemplateStep step = (SelectTemplateStep)myWizard.getCurrentStepObject();
+    boolean condition = step.setSelectedTemplate(group, name);
+    if (!condition) {
+      throw new IllegalArgumentException(group + "/" + name + " template not found");
+    }
+    ProjectTemplate template = step.getSelectedTemplate();
+    assertNotNull(template);
+
+    if (adjuster != null) {
+      adjuster.consume(step);
+    }
+
+    runWizard(adjuster);
+  }
+
+  protected void createWizard(Project project) throws IOException {
+    File directory = FileUtil.createTempDirectory(getName(), "new", false);
+    myFilesToDelete.add(directory);
+    myWizard = new AddModuleWizard(project, DefaultModulesProvider.createForProject(project), directory.getPath());
+    UIUtil.dispatchAllInvocationEvents(); // to make default selection applied
+  }
+
+  protected void runWizard(Consumer<ModuleWizardStep> adjuster) {
+    while (!myWizard.isLast()) {
+      myWizard.doNextAction();
+      if (adjuster != null) {
+        adjuster.consume(myWizard.getCurrentStepObject());
+      }
+    }
+    myWizard.doOk();
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    Sdk projectSdk = ProjectRootManager.getInstance(getProject()).getProjectSdk();
+    Sdk[] jdks = ProjectJdkTable.getInstance().getAllJdks();
+    for (final Sdk jdk : jdks) {
+      if (projectSdk != jdk) {
+        ApplicationManager.getApplication().runWriteAction(new Runnable() {
+          public void run() {
+            ProjectJdkTable.getInstance().removeJdk(jdk);
+          }
+        });
+      }
+    }
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    if (myWizard != null) {
+      Disposer.dispose(myWizard.getDisposable());
+    }
+    if (myCreatedProject != null) {
+      myProjectManager.closeProject(myCreatedProject);
+      ApplicationManager.getApplication().runWriteAction(new Runnable() {
+        @Override
+        public void run() {
+          Disposer.dispose(myCreatedProject);
+        }
+      });
+    }
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        for (Sdk sdk : mySdks) {
+          ProjectJdkTable.getInstance().removeJdk(sdk);
+        }
+      }
+    });
+    super.tearDown();
+  }
+
+  protected Module importModuleFrom(ProjectImportProvider provider, String path) {
+    return importFrom(path, getProject(), null, provider);
+  }
+
+  protected Module importProjectFrom(String path, Consumer<ModuleWizardStep> adjuster, ProjectImportProvider... providers) {
+    Module module = importFrom(path, null, adjuster, providers);
+    if (module != null) {
+      myCreatedProject = module.getProject();
+    }
+    return module;
+  }
+
+  private Module importFrom(String path,
+                            @Nullable Project project, Consumer<ModuleWizardStep> adjuster,
+                            final ProjectImportProvider... providers) {
+    VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
+    assertNotNull("Can't find " + path, file);
+    assertTrue(providers[0].canImport(file, project));
+
+    myWizard = ImportModuleAction.createImportWizard(project, null, file, providers);
+    if (myWizard.getStepCount() > 0) {
+      runWizard(adjuster);
+    }
+    List<Module> modules = ImportModuleAction.createFromWizard(project, myWizard);
+    return modules == null || modules.isEmpty() ? null : modules.get(0);
+  }
+
+  protected Sdk createSdk(String name, SdkTypeId sdkType) {
+    final Sdk sdk = ProjectJdkTable.getInstance().createSdk(name, sdkType);
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        ProjectJdkTable.getInstance().addJdk(sdk);
+      }
+    });
+    mySdks.add(sdk);
+    return sdk;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/mock/MockPsiDirectory.java b/java/testFramework/src/com/intellij/mock/MockPsiDirectory.java
new file mode 100644
index 0000000..b451b29
--- /dev/null
+++ b/java/testFramework/src/com/intellij/mock/MockPsiDirectory.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
+ */
+package com.intellij.mock;
+
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.search.PsiElementProcessor;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.lang.Language;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author peter
+ */
+public class MockPsiDirectory extends MockPsiElement implements PsiDirectory {
+  private final PsiPackage myPackage;
+
+  public MockPsiDirectory(final PsiPackage aPackage, @NotNull Disposable parentDisposable) {
+    super(parentDisposable);
+    myPackage = aPackage;
+  }
+
+  @Override
+  public boolean isDirectory() {
+    return true;
+  }
+
+  @NotNull
+  @Override
+  public Language getLanguage() {
+    return Language.ANY;
+  }
+
+  @Override
+  public void checkCreateFile(@NotNull final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method checkCreateFile is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  public void checkCreateSubdirectory(@NotNull final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method checkCreateSubdirectory is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  public PsiDirectory getParent() {
+    return getParentDirectory();
+  }
+
+
+  @Override
+  @NotNull
+  public PsiFile createFile(@NotNull final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method createFile is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public PsiFile copyFileFrom(@NotNull final String newName, @NotNull final PsiFile originalFile) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method copyFileFrom is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public PsiDirectory createSubdirectory(@NotNull final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method createSubdirectory is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @Nullable
+  public PsiFile findFile(@NotNull @NonNls final String name) {
+    throw new UnsupportedOperationException("Method findFile is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @Nullable
+  public PsiDirectory findSubdirectory(@NotNull final String name) {
+    throw new UnsupportedOperationException("Method findSubdirectory is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public PsiFile[] getFiles() {
+    throw new UnsupportedOperationException("Method getFiles is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public String getName() {
+    throw new UnsupportedOperationException("Method getName is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @Nullable
+  public PsiDirectory getParentDirectory() {
+    final PsiPackage psiPackage = myPackage.getParentPackage();
+    return psiPackage == null ? null : new MockPsiDirectory(psiPackage, getProject());
+  }
+
+  @Override
+  @NotNull
+  public PsiDirectory[] getSubdirectories() {
+    throw new UnsupportedOperationException("Method getSubdirectories is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public VirtualFile getVirtualFile() {
+    throw new UnsupportedOperationException("Method getVirtualFile is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  public boolean processChildren(final PsiElementProcessor<PsiFileSystemItem> processor) {
+    throw new UnsupportedOperationException("Method processChildren is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @NotNull
+  public PsiElement setName(@NotNull final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method setName is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  public void checkSetName(final String name) throws IncorrectOperationException {
+    throw new IncorrectOperationException("Method checkSetName is not yet implemented in " + getClass().getName());
+  }
+
+  @Override
+  @Nullable
+  public ItemPresentation getPresentation() {
+    throw new UnsupportedOperationException("Method getPresentation is not yet implemented in " + getClass().getName());
+  }
+}
diff --git a/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java
new file mode 100644
index 0000000..7979272
--- /dev/null
+++ b/java/testFramework/src/com/intellij/projectView/BaseProjectViewTestCase.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.projectView;
+
+import com.intellij.ide.SelectInTarget;
+import com.intellij.ide.projectView.BaseProjectTreeBuilder;
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.*;
+import com.intellij.ide.projectView.impl.nodes.PackageElementNode;
+import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.ide.util.treeView.*;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.project.DumbAwareRunnable;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.ui.Queryable;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.testFramework.ProjectViewTestUtil;
+import com.intellij.testFramework.TestSourceBasedTestCase;
+import com.intellij.util.Function;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+public abstract class BaseProjectViewTestCase extends TestSourceBasedTestCase {
+  protected AbstractTreeStructure myStructure;
+  protected boolean myShowMembers = false;
+  protected boolean myHideEmptyMiddlePackages;
+  protected boolean myFlattenPackages;
+
+  private List<AbstractProjectViewPSIPane> myPanes = new ArrayList<AbstractProjectViewPSIPane>();
+
+  protected Queryable.PrintInfo myPrintInfo;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    myStructure = new TestProjectTreeStructure(myProject) {
+      @Override
+      public boolean isShowMembers() {
+        return myShowMembers;
+      }
+
+      @Override
+      public boolean isHideEmptyMiddlePackages() {
+        return myHideEmptyMiddlePackages;
+      }
+
+      @Override
+      public boolean isFlattenPackages() {
+        return myFlattenPackages;
+      }
+    };
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    for (final AbstractProjectViewPSIPane myPane : myPanes) {
+      Disposer.dispose(myPane);
+    }
+    myPanes = null;
+    myStructure = null;
+    super.tearDown();
+  }
+
+  protected AbstractProjectViewPSIPane createPane() {
+    final AbstractProjectViewPSIPane pane = new MyAbstractProjectViewPSIPane();
+    pane.createComponent();
+    myPanes.add(pane);
+    return pane;
+  }
+
+  protected void assertStructureEqual(PsiDirectory packageDirectory, @NonNls String expected) {
+    assertStructureEqual(packageDirectory, expected, 17, myStructure);
+  }
+
+  protected void assertStructureEqual(PsiDirectory packageDirectory, @NonNls String expected, int maxRowCount) {
+    assertStructureEqual(packageDirectory, expected, maxRowCount, myStructure);
+  }
+
+  protected void useStandardProviders() {
+    getProjectTreeStructure().setProviders(new ClassesTreeStructureProvider(myProject));
+  }
+
+  protected AbstractProjectTreeStructure getProjectTreeStructure() {
+    return (AbstractProjectTreeStructure)myStructure;
+  }
+
+  protected void assertStructureEqual(String expected, Comparator comparator) {
+    assertStructureEqual(myStructure.getRootElement(), expected, 27, comparator);
+  }
+
+  private void assertStructureEqual(PsiDirectory root, String expected, int maxRowCount, AbstractTreeStructure structure) {
+    assertNotNull(root);
+    PsiDirectoryNode rootNode = new PsiDirectoryNode(myProject, root, (ViewSettings)structure);
+    assertStructureEqual(rootNode, expected, maxRowCount, PlatformTestUtil.createComparator(myPrintInfo));
+  }
+
+  private void assertStructureEqual(Object rootNode, String expected, int maxRowCount, Comparator comparator) {
+    checkGetParentConsistency(rootNode);
+    String actual = PlatformTestUtil.print(myStructure, rootNode, 0, comparator, maxRowCount, ' ', myPrintInfo).toString();
+    assertEquals(expected, actual);
+  }
+
+  private void checkGetParentConsistency(Object from) {
+    Object[] childElements = myStructure.getChildElements(from);
+    for (Object childElement : childElements) {
+      assertSame(from, myStructure.getParentElement(childElement));
+      checkGetParentConsistency(childElement);
+    }
+  }
+
+  protected static boolean isExpanded(DefaultMutableTreeNode nodeForElement, AbstractProjectViewPSIPane pane) {
+    TreePath path = new TreePath(nodeForElement.getPath());
+    return pane.getTree().isExpanded(path.getParentPath());
+  }
+
+  protected static DefaultMutableTreeNode getNodeForElement(PsiElement element, AbstractProjectViewPSIPane pane) {
+    JTree tree = pane.getTree();
+    TreeModel model = tree.getModel();
+    Object root = model.getRoot();
+    return getNodeForElement(root, model, element);
+  }
+
+  private static DefaultMutableTreeNode getNodeForElement(Object root, TreeModel model, PsiElement element) {
+    if (root instanceof DefaultMutableTreeNode) {
+      Object userObject = ((DefaultMutableTreeNode)root).getUserObject();
+      if (userObject instanceof AbstractTreeNode) {
+        AbstractTreeNode treeNode = (AbstractTreeNode)userObject;
+        if (element.equals(treeNode.getValue())) return (DefaultMutableTreeNode)root;
+        for (int i = 0; i < model.getChildCount(root); i++) {
+          DefaultMutableTreeNode nodeForChild = getNodeForElement(model.getChild(root, i), model, element);
+          if (nodeForChild != null) return nodeForChild;
+        }
+      }
+    }
+    return null;
+  }
+
+  public static void checkNavigateFromSourceBehaviour(PsiElement element, VirtualFile virtualFile, AbstractProjectViewPSIPane pane) {
+    Disposer.dispose(pane);
+    pane.createComponent();
+    assertNull(getNodeForElement(element, pane));
+    pane.select(element, virtualFile, true);
+    assertTrue(isExpanded(element, pane));
+  }
+
+  public static boolean isExpanded(PsiElement element, AbstractProjectViewPSIPane pane) {
+    DefaultMutableTreeNode nodeForElement = getNodeForElement(element, pane);
+    return nodeForElement != null && isExpanded((DefaultMutableTreeNode)nodeForElement.getParent(), pane);
+  }
+
+  protected static void assertListsEqual(ListModel model, String expected) {
+    assertEquals(expected, PlatformTestUtil.print(model));
+  }
+
+  public static void checkContainsMethod(final Object rootElement, final AbstractTreeStructure structure) {
+    ProjectViewTestUtil.checkContainsMethod(rootElement, structure, new Function<AbstractTreeNode, VirtualFile[]>() {
+      @Override
+      public VirtualFile[] fun(AbstractTreeNode kid) {
+        if (kid instanceof PackageElementNode) {
+          return ((PackageElementNode)kid).getVirtualFiles();
+        }
+        return null;
+      }
+    });
+  }
+
+  @Override
+  protected String getTestPath() {
+    return "projectView";
+  }
+
+  protected static String getPackageRelativePath() {
+    return "com/package1";
+  }
+
+  protected PsiDirectory getPackageDirectory() {
+    return getPackageDirectory(getPackageRelativePath());
+  }
+
+  private class MyAbstractProjectViewPSIPane extends AbstractProjectViewPSIPane {
+    public MyAbstractProjectViewPSIPane() {
+      super(BaseProjectViewTestCase.this.myProject);
+    }
+
+    @Override
+    public SelectInTarget createSelectInTarget() {
+      return null;
+    }
+
+    @NonNls
+    public String getComponentName() {
+      return "comp name";
+    }
+
+    @Override
+    protected AbstractTreeUpdater createTreeUpdater(AbstractTreeBuilder treeBuilder) {
+      return new AbstractTreeUpdater(treeBuilder);
+    }
+
+    @Override
+    @NotNull
+    protected BaseProjectTreeBuilder createBuilder(DefaultTreeModel treeModel) {
+      return new ProjectTreeBuilder(myProject, myTree, treeModel, AlphaComparator.INSTANCE,
+                                    (ProjectAbstractTreeStructureBase)myTreeStructure) {
+        @Override
+        protected AbstractTreeUpdater createUpdater() {
+          return createTreeUpdater(this);
+        }
+
+        protected void addTaskToWorker(final Runnable runnable, boolean first, final Runnable postRunnable) {
+          runnable.run();
+          postRunnable.run();
+        }
+      };
+    }
+
+    @Override
+    protected ProjectAbstractTreeStructureBase createStructure() {
+      return (ProjectAbstractTreeStructureBase)myStructure;
+    }
+
+    @Override
+    protected ProjectViewTree createTree(DefaultTreeModel treeModel) {
+      return new ProjectViewTree(myProject, treeModel) {
+        @Override
+        public DefaultMutableTreeNode getSelectedNode() {
+          return null;
+        }
+      };
+    }
+
+    @Override
+    public Icon getIcon() {
+      return null;
+    }
+
+    @Override
+    @NotNull
+    public String getId() {
+      return "";
+    }
+
+    @Override
+    public String getTitle() {
+      return null;
+    }
+
+    @Override
+    public int getWeight() {
+      return 0;
+    }
+
+    public void projectOpened() {
+      final Runnable runnable = new DumbAwareRunnable() {
+        @Override
+        public void run() {
+          final ProjectView projectView = ProjectView.getInstance(myProject);
+          projectView.addProjectPane(MyAbstractProjectViewPSIPane.this);
+        }
+      };
+      StartupManager.getInstance(myProject).registerPostStartupActivity(runnable);
+    }
+
+    public void projectClosed() {
+    }
+
+    public void initComponent() { }
+
+    public void disposeComponent() {
+
+    }
+  }
+
+  @Override
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath(getClass());
+  }
+
+  @Override
+  protected boolean isRunInWriteAction() {
+    return false;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/projectView/TestProjectTreeStructure.java b/java/testFramework/src/com/intellij/projectView/TestProjectTreeStructure.java
new file mode 100644
index 0000000..40a42a1
--- /dev/null
+++ b/java/testFramework/src/com/intellij/projectView/TestProjectTreeStructure.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.projectView;
+
+import com.intellij.ide.projectView.impl.AbstractProjectTreeStructure;
+import com.intellij.openapi.project.Project;
+
+class TestProjectTreeStructure extends AbstractProjectTreeStructure {
+  public TestProjectTreeStructure(Project project) {
+    super(project);
+  }
+
+  @Override
+  public boolean isShowMembers() {
+    return false;
+  }
+
+  @Override
+  public boolean isFlattenPackages() {
+    return false;
+  }
+
+  @Override
+  public boolean isAbbreviatePackageNames() {
+    return false;
+  }
+
+  @Override
+  public boolean isHideEmptyMiddlePackages() {
+    return false;
+  }
+
+  @Override
+  public boolean isShowLibraryContents() {
+    return true;
+  }
+
+  @Override
+  public boolean isShowModules() {
+    return true;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java
new file mode 100644
index 0000000..43bf6cc
--- /dev/null
+++ b/java/testFramework/src/com/intellij/psi/AbstractReparseTestCase.java
@@ -0,0 +1,105 @@
+package com.intellij.psi;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.impl.source.SourceTreeToPsiMap;
+import com.intellij.psi.text.BlockSupport;
+import com.intellij.testFramework.PsiTestCase;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * @author maxim
+ */
+public abstract class AbstractReparseTestCase extends PsiTestCase {
+  protected FileType myFileType;
+  protected PsiFile myDummyFile;
+  private int myInsertOffset;
+
+  protected void setFileType(final FileType fileType) {
+    myFileType = fileType;
+  }
+
+  protected void insert(@NonNls final String s) throws IncorrectOperationException {
+    CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
+      @Override
+      public void run() {
+        ApplicationManager.getApplication().runWriteAction(new Runnable() {
+          @Override
+          public void run() {
+            String oldText = myDummyFile.getText();
+            String expectedNewText = oldText.substring(0, myInsertOffset) + s + oldText.substring(myInsertOffset);
+
+            try {
+              doReparse(s, expectedNewText, 0);
+            }
+            catch (IncorrectOperationException e) {
+              LOG.error(e);
+            }
+            myInsertOffset += s.length();
+          }
+        });
+      }
+    }, "asd", null);
+  }
+
+  protected void moveEditPointLeft(int count) {
+    myInsertOffset -= count;
+  }
+
+  protected void moveEditPointRight(int count) {
+    myInsertOffset += count;
+  }
+
+  protected void setEditPoint(int pos) {
+    myInsertOffset = pos;
+  }
+
+  protected void remove(int count) throws IncorrectOperationException {
+    String oldText = myDummyFile.getText();
+    String expectedNewText = oldText.substring(0, myInsertOffset-count) + oldText.substring(myInsertOffset);
+
+    doReparse("", expectedNewText, count);
+    myInsertOffset -= count;
+  }
+
+  protected void doReparse(final String s, final String expectedNewText, final int length) throws IncorrectOperationException {
+    CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() {
+      @Override
+      public void run() {
+        ApplicationManager.getApplication().runWriteAction(new Runnable() {
+          @Override
+          public void run() {
+            BlockSupport blockSupport = ServiceManager.getService(myProject, BlockSupport.class);
+            try {
+              blockSupport.reparseRange(myDummyFile, myInsertOffset - length, myInsertOffset, s);
+              String foundStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(myDummyFile), false);
+              final PsiFile psiFile = createDummyFile(getName() + "." + myFileType.getDefaultExtension(), expectedNewText);
+              String expectedStructure = DebugUtil.treeToString(SourceTreeToPsiMap.psiElementToTree(psiFile), false);
+              if (!expectedStructure.equals(foundStructure)) {
+                System.out.println("expected: ");
+                System.out.println(expectedStructure);
+                System.out.println("found: ");
+                System.out.println(foundStructure);
+                assertEquals(expectedStructure, foundStructure);
+              }
+
+              assertEquals("Reparse tree should be equal to the document",expectedNewText,myDummyFile.getText());
+            }
+            catch (IncorrectOperationException e) {
+              LOG.error(e);
+            }
+          }
+        });
+      }
+    }, "asd", null);
+  }
+
+  protected void prepareFile(@NonNls String prefix, @NonNls String suffix) throws IncorrectOperationException {
+    myDummyFile = createDummyFile(getName() + "." + myFileType.getDefaultExtension(), prefix + suffix);
+    myInsertOffset = prefix.length();
+  }
+}
diff --git a/java/testFramework/src/com/intellij/refactoring/MockInlineMethodOptions.java b/java/testFramework/src/com/intellij/refactoring/MockInlineMethodOptions.java
new file mode 100644
index 0000000..3d070ef
--- /dev/null
+++ b/java/testFramework/src/com/intellij/refactoring/MockInlineMethodOptions.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.refactoring;
+
+import com.intellij.refactoring.inline.InlineOptions;
+
+/**
+ * @author dyoma
+ */
+public class MockInlineMethodOptions implements InlineOptions {
+  @Override
+  public boolean isInlineThisOnly() {
+    return false;
+  }
+
+  @Override
+  public void close(int exitCode) {
+  }
+
+  @Override
+  public boolean isPreviewUsages() {
+    return false;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/refactoring/MultiFileTestCase.java b/java/testFramework/src/com/intellij/refactoring/MultiFileTestCase.java
new file mode 100644
index 0000000..b21347b
--- /dev/null
+++ b/java/testFramework/src/com/intellij/refactoring/MultiFileTestCase.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.refactoring;
+
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.impl.source.PostprocessReformattingAspect;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.testFramework.PsiTestUtil;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+
+/**
+ * @author dsl
+ */
+public abstract class MultiFileTestCase extends CodeInsightTestCase {
+  protected boolean myDoCompare = true;
+
+  protected void doTest(final PerformAction performAction) throws Exception {
+    doTest(performAction, getTestName(true));
+  }
+
+  protected void doTest(final PerformAction performAction, final boolean lowercaseFirstLetter) throws Exception {
+    doTest(performAction, getTestName(lowercaseFirstLetter));
+  }
+
+  protected void doTest(final PerformAction performAction, final String testName) throws Exception {
+    String path = getTestDataPath() + getTestRoot() + testName;
+
+    String pathBefore = path + "/before";
+    final VirtualFile rootDir = PsiTestUtil.createTestProjectStructure(myProject, myModule, pathBefore, myFilesToDelete, false);
+    prepareProject(rootDir);
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    String pathAfter = path + "/after";
+    final VirtualFile rootAfter = LocalFileSystem.getInstance().findFileByPath(pathAfter.replace(File.separatorChar, '/'));
+
+    performAction.performAction(rootDir, rootAfter);
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        myProject.getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
+      }
+    });
+
+    FileDocumentManager.getInstance().saveAllDocuments();
+
+    if (myDoCompare) {
+      PlatformTestUtil.assertDirectoriesEqual(rootAfter, rootDir, PlatformTestUtil.CVS_FILE_FILTER);
+    }
+  }
+
+  protected void prepareProject(VirtualFile rootDir) {
+    PsiTestUtil.addSourceContentToRoots(myModule, rootDir);
+  }
+
+  @Override
+  @NonNls
+  protected abstract String getTestRoot();
+
+  protected interface PerformAction {
+    void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception;
+  }
+
+  @Override
+  protected boolean isRunInWriteAction() {
+    return false;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java
new file mode 100644
index 0000000..bc6b747
--- /dev/null
+++ b/java/testFramework/src/com/intellij/refactoring/move/moveMembers/MockMoveMembersOptions.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.refactoring.move.moveMembers;
+
+import com.intellij.psi.PsiMember;
+import com.intellij.psi.PsiModifier;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * @author dyoma
+ */
+public class MockMoveMembersOptions implements MoveMembersOptions {
+  private final PsiMember[] mySelectedMembers;
+  private final String myTargetClassName;
+  private String myMemberVisibility = PsiModifier.PUBLIC;
+
+  public MockMoveMembersOptions(String targetClassName, PsiMember[] selectedMembers) {
+    mySelectedMembers = selectedMembers;
+    myTargetClassName = targetClassName;
+  }
+
+  public MockMoveMembersOptions(String targetClassName, Collection<PsiMember> memberSet) {
+    this(targetClassName, memberSet.toArray(new PsiMember[memberSet.size()]));
+  }
+
+  @Override
+  public String getMemberVisibility() {
+    return myMemberVisibility;
+  }
+
+  @Override
+  public boolean makeEnumConstant() {
+    return true;
+  }
+
+  public void setMemberVisibility(@Nullable String visibility) {
+    myMemberVisibility = visibility;
+  }
+
+  @Override
+  public PsiMember[] getSelectedMembers() {
+    return mySelectedMembers;
+  }
+
+  @Override
+  public String getTargetClassName() {
+    return myTargetClassName;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/EditorActionTestCase.java b/java/testFramework/src/com/intellij/testFramework/EditorActionTestCase.java
new file mode 100644
index 0000000..a50e044
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/EditorActionTestCase.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.psi.PsiDocumentManager;
+
+import java.io.IOException;
+
+/**
+ * A TestCase for testing some action in editor
+ */
+public abstract class EditorActionTestCase extends LightCodeInsightTestCase {
+  /**
+   * @return id of the action to be tested.
+   */
+  protected abstract String getActionId();
+
+  /**
+   * Perform action test using text before and after action perform. Useas &lt;caret&gt; marker where caret should be
+   * placed when file is loaded in editor and &lt;selection&gt;&lt;/selection&gt; denoting selection bounds.
+   * @param fileName name of the file. Mostly used to create proper instance of the PsiFile
+   * @param textBefore text with markers before action
+   * @param textAfter expected text with markers after action
+   * @throws IOException
+   */
+  protected void doTextTest(String fileName, String textBefore, String textAfter) throws IOException {
+    doTextTest(fileName, textBefore, textAfter, false);
+  }
+
+  /**
+   * Perform action test using text before and after action perform. Uses &lt;caret&gt; marker where caret should be
+   * placed when file is loaded in editor and &lt;selection&gt;&lt;/selection&gt; denoting selection bounds.
+   * @param fileName  name of the file. Mostly used to create proper instance of the PsiFile
+   * @param textBefore  text with markers before action
+   * @param textAfter  expected text with markers after action
+   * @param ignoreTrailingSpaces  true if trailing spaces should be ignored.
+   * @throws IOException
+   */
+  protected void doTextTest(String fileName, String textBefore, String textAfter, boolean ignoreTrailingSpaces) throws IOException {
+    configureFromFileText(fileName, textBefore);
+    invokeAction();
+    PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+    assertEquals("Reparse error!", myEditor.getDocument().getText(), myFile.getText());
+    checkResultByText(null, textAfter, ignoreTrailingSpaces);
+  }
+
+  /**
+   * Same as doTextTest but texts are retrieved from the data files.
+   * @param filePathBefore source file's relative path from %IDEA_INSTALLATION_HOME%/testData/
+   * @param filePathAfter expected file's relative path from %IDEA_INSTALLATION_HOME%/testData/
+   * @throws Exception
+   */
+  protected void doFileTest(String filePathBefore, String filePathAfter) throws Exception {
+    doFileTest(filePathBefore, filePathAfter, false);
+  }
+
+  /**
+   * Same as doTextTest but texts are retrieved from the data files.
+   * @param filePathBefore source file's relative path from %IDEA_INSTALLATION_HOME%/testData/
+   * @param filePathAfter expected file's relative path from %IDEA_INSTALLATION_HOME%/testData/
+   * @param ignoreTrailingSpaces  true if trailing spaces should be ignored.
+   * @throws Exception
+   */
+  protected void doFileTest(String filePathBefore, String filePathAfter, boolean ignoreTrailingSpaces) throws Exception {
+    configureByFile(filePathBefore);
+    invokeAction();
+    checkResultByFile(null, filePathAfter, ignoreTrailingSpaces);
+  }
+
+  private void invokeAction() {
+    final String actionId = getActionId();
+    final AnAction action = ActionManager.getInstance().getAction(actionId);
+    //noinspection HardCodedStringLiteral
+    assertNotNull("Can find registered action with id=" + actionId, action);
+    action.actionPerformed(
+        new AnActionEvent(
+            null,
+            DataManager.getInstance().getDataContext(),
+            "",
+            action.getTemplatePresentation(),
+            ActionManager.getInstance(),
+            0
+        )
+    );
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java b/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java
new file mode 100644
index 0000000..93e357c
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/IdeaTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.vfs.impl.VirtualFilePointerManagerImpl;
+import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * @author mike
+ */
+public abstract class IdeaTestCase extends PlatformTestCase {
+  protected JavaPsiFacadeEx myJavaFacade;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myJavaFacade = JavaPsiFacadeEx.getInstanceEx(myProject);
+    VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
+    filePointerManager.storePointers();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    myJavaFacade = null;
+    super.tearDown();
+    VirtualFilePointerManagerImpl filePointerManager = (VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance();
+    filePointerManager.assertPointersAreDisposed();
+  }
+
+  public final JavaPsiFacadeEx getJavaFacade() {
+    return myJavaFacade;
+  }
+
+  @Override
+  protected Sdk getTestProjectJdk() {
+    return IdeaTestUtil.getMockJdk17();
+  }
+
+  @Override
+  protected ModuleType getModuleType() {
+    return StdModuleTypes.JAVA;
+  }
+
+  public static void initPlatformPrefix() {
+    initPlatformPrefix("com.intellij.idea.IdeaUltimateApplication", "Idea");
+  }
+
+  protected static void sortClassesByName(final PsiClass[] classes) {
+    Arrays.sort(classes, new Comparator<PsiClass>() {
+      @Override
+      public int compare(PsiClass o1, PsiClass o2) {
+        return o1.getName().compareTo(o2.getName());
+      }
+    });
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java b/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java
new file mode 100644
index 0000000..0f94f6a
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/IdeaTestUtil.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkModificator;
+import com.intellij.openapi.roots.LanguageLevelModuleExtension;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.java.LanguageLevel;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+public class IdeaTestUtil extends PlatformTestUtil {
+  public static void main(String[] args) {
+    printDetectedPerformanceTimings();
+  }
+
+  @SuppressWarnings({"UseOfSystemOutOrSystemErr"})
+  public static void printDetectedPerformanceTimings() {
+    System.out.println(Timings.getStatistics());
+  }
+
+  public static void withLevel(final Module module, final LanguageLevel level, final Runnable r) {
+    final LanguageLevelProjectExtension projectExt = LanguageLevelProjectExtension.getInstance(module.getProject());
+
+    final LanguageLevel projectLevel = projectExt.getLanguageLevel();
+    final LanguageLevel moduleLevel = LanguageLevelModuleExtension.getInstance(module).getLanguageLevel();
+    try {
+      projectExt.setLanguageLevel(level);
+      setModuleLanguageLevel(module, level);
+      r.run();
+    }
+    finally {
+      setModuleLanguageLevel(module, moduleLevel);
+      projectExt.setLanguageLevel(projectLevel);
+    }
+  }
+
+  public static void setModuleLanguageLevel(Module module, final LanguageLevel level) {
+    final LanguageLevelModuleExtension modifiable = (LanguageLevelModuleExtension)LanguageLevelModuleExtension.getInstance(module).getModifiableModel(true);
+    modifiable.setLanguageLevel(level);
+    modifiable.commit();
+  }
+
+  public static Sdk getMockJdk17() {
+    return getMockJdk17("java 1.7");
+  }
+
+  public static Sdk getMockJdk17(@NotNull String name) {
+    return JavaSdk.getInstance().createJdk(name, getMockJdk17Path().getPath(), false);
+  }
+
+  public static Sdk getMockJdk14() {
+    return JavaSdk.getInstance().createJdk("java 1.4", getMockJdk14Path().getPath(), false);
+  }
+
+  public static File getMockJdk14Path() {
+    return getPathForJdkNamed("mockJDK-1.4");
+  }
+
+  public static File getMockJdk17Path() {
+    return getPathForJdkNamed("mockJDK-1.7");
+  }
+
+  private static File getPathForJdkNamed(String name) {
+    File mockJdkCEPath = new File(PathManager.getHomePath(), "java/" + name);
+    return mockJdkCEPath.exists() ? mockJdkCEPath : new File(PathManager.getHomePath(), "community/java/" + name);
+  }
+
+  public static Sdk getWebMockJdk17() {
+    Sdk jdk = getMockJdk17();
+    addWebJarsTo(jdk);
+    return jdk;
+  }
+
+  public static void addWebJarsTo(@NotNull Sdk jdk) {
+    SdkModificator sdkModificator = jdk.getSdkModificator();
+    sdkModificator.addRoot(findJar("lib/jsp-api.jar"), OrderRootType.CLASSES);
+    sdkModificator.addRoot(findJar("lib/servlet-api.jar"), OrderRootType.CLASSES);
+    sdkModificator.commitChanges();
+  }
+
+  private static VirtualFile findJar(String name) {
+    String path = PathManager.getHomePath() + '/' + name;
+    VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path);
+    assert file != null : "not found: " + path;
+    VirtualFile jar = JarFileSystem.getInstance().getJarRootForLocalFile(file);
+    assert jar != null : "no .jar for: " + path;
+    return jar;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java b/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java
new file mode 100644
index 0000000..a93ea6b
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/InspectionTestCase.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.ExtensionPoints;
+import com.intellij.analysis.AnalysisScope;
+import com.intellij.codeInspection.GlobalInspectionTool;
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection;
+import com.intellij.codeInspection.ex.*;
+import com.intellij.codeInspection.reference.EntryPoint;
+import com.intellij.codeInspection.reference.RefElement;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.util.PsiUtilCore;
+import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
+import com.intellij.util.ArrayUtil;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * @author max
+ * @since Apr 11, 2002
+ */
+@SuppressWarnings({"HardCodedStringLiteral"})
+public abstract class InspectionTestCase extends PsiTestCase {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.testFramework.InspectionTestCase");
+  private EntryPoint myUnusedCodeExtension;
+  private VirtualFile ext_src;
+
+  public InspectionManagerEx getManager() {
+    return (InspectionManagerEx)InspectionManager.getInstance(myProject);
+  }
+
+  public void doTest(@NonNls String folderName, LocalInspectionTool tool) {
+    doTest(folderName, new LocalInspectionToolWrapper(tool));
+  }
+
+  public void doTest(@NonNls String folderName, GlobalInspectionTool tool) {
+    doTest(folderName, new GlobalInspectionToolWrapper(tool));
+  }
+
+  public void doTest(@NonNls String folderName, GlobalInspectionTool tool, boolean checkRange) {
+    doTest(folderName, new GlobalInspectionToolWrapper(tool), checkRange);
+  }
+
+  public void doTest(@NonNls String folderName, GlobalInspectionTool tool, boolean checkRange, boolean runDeadCodeFirst) {
+    doTest(folderName, new GlobalInspectionToolWrapper(tool), "java 1.4", checkRange, runDeadCodeFirst);
+  }
+
+  public void doTest(@NonNls String folderName, InspectionTool tool) {
+    doTest(folderName, tool, "java 1.4");
+  }
+
+  public void doTest(@NonNls String folderName, InspectionTool tool, final boolean checkRange) {
+    doTest(folderName, tool, "java 1.4", checkRange);
+  }
+
+  public void doTest(@NonNls String folderName, LocalInspectionTool tool, @NonNls final String jdkName) {
+    doTest(folderName, new LocalInspectionToolWrapper(tool), jdkName);
+  }
+
+  public void doTest(@NonNls String folderName, InspectionTool tool, @NonNls final String jdkName) {
+    doTest(folderName, tool, jdkName, false);
+  }
+
+  public void doTest(@NonNls String folderName, InspectionTool tool, @NonNls final String jdkName, boolean checkRange) {
+    doTest(folderName, tool, jdkName, checkRange, false);
+  }
+
+  public void doTest(@NonNls String folderName,
+                     InspectionTool tool,
+                     @NonNls final String jdkName,
+                     boolean checkRange,
+                     boolean runDeadCodeFirst,
+                     InspectionTool... additional) {
+    final String testDir = getTestDataPath() + "/" + folderName;
+    runTool(testDir, jdkName, runDeadCodeFirst, tool, additional);
+
+    InspectionTestUtil.compareToolResults(tool, checkRange, testDir);
+  }
+
+  protected void runTool(@NonNls final String testDir, @NonNls final String jdkName, final InspectionTool tool) {
+    runTool(testDir, jdkName, false, tool);
+  }
+
+  protected void runTool(final String testDir,
+                         final String jdkName,
+                         boolean runDeadCodeFirst,
+                         final InspectionTool tool,
+                         InspectionTool... additional) {
+    final VirtualFile[] sourceDir = new VirtualFile[1];
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        try {
+          setupRootModel(testDir, sourceDir, jdkName);
+        }
+        catch (Exception e) {
+          LOG.error(e);
+        }
+      }
+    });
+    AnalysisScope scope = createAnalysisScope(sourceDir[0].getParent());
+
+    InspectionManagerEx inspectionManager = (InspectionManagerEx)InspectionManager.getInstance(getProject());
+    InspectionTool[] tools = runDeadCodeFirst ? new InspectionTool[]{new UnusedDeclarationInspection(), tool} : new InspectionTool[]{tool};
+    tools = ArrayUtil.mergeArrays(tools, additional);
+    final GlobalInspectionContextImpl globalContext =
+      CodeInsightTestFixtureImpl.createGlobalContextForTool(scope, getProject(), inspectionManager, tools);
+
+    InspectionTestUtil.runTool(tool, scope, globalContext, inspectionManager);
+  }
+
+  protected AnalysisScope createAnalysisScope(VirtualFile sourceDir) {
+    PsiManager psiManager = PsiManager.getInstance(myProject);
+    return new AnalysisScope(psiManager.findDirectory(sourceDir));
+  }
+
+  protected void setupRootModel(final String testDir, final VirtualFile[] sourceDir, final String sdkName) {
+    VirtualFile projectDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(testDir));
+    assertNotNull("could not find project dir " + testDir, projectDir);
+    sourceDir[0] = projectDir.findChild("src");
+    if (sourceDir[0] == null) {
+      sourceDir[0] = projectDir;
+    }
+    // IMPORTANT! The jdk must be obtained in a way it is obtained in the normal program!
+    //ProjectJdkEx jdk = ProjectJdkTable.getInstance().getInternalJdk();
+    PsiTestUtil.removeAllRoots(myModule, getTestProjectSdk());
+    PsiTestUtil.addContentRoot(myModule, projectDir);
+    PsiTestUtil.addSourceRoot(myModule, sourceDir[0]);
+    ext_src = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(testDir + "/ext_src"));
+    if (ext_src != null) {
+      PsiTestUtil.addSourceRoot(myModule, ext_src);
+    }
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL);
+    myUnusedCodeExtension = new EntryPoint() {
+      @NotNull
+      @Override
+      public String getDisplayName() {
+        return "duh";
+      }
+
+      @Override
+      public boolean isEntryPoint(RefElement refElement, PsiElement psiElement) {
+        return isEntryPoint(psiElement);
+      }
+
+      @Override
+      public boolean isEntryPoint(PsiElement psiElement) {
+        return ext_src != null && VfsUtilCore.isAncestor(ext_src, PsiUtilCore.getVirtualFile(psiElement), false);
+      }
+
+      @Override
+      public boolean isSelected() {
+        return false;
+      }
+
+      @Override
+      public void setSelected(boolean selected) {
+
+      }
+
+      @Override
+      public void readExternal(Element element) {
+
+      }
+
+      @Override
+      public void writeExternal(Element element) {
+
+      }
+    };
+
+    point.registerExtension(myUnusedCodeExtension);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    ExtensionPoint<EntryPoint> point = Extensions.getRootArea().getExtensionPoint(ExtensionPoints.DEAD_CODE_TOOL);
+    point.unregisterExtension(myUnusedCodeExtension);
+    myUnusedCodeExtension = null;
+    ext_src = null;
+    super.tearDown();
+  }
+
+  @Override
+  protected void setUpJdk() {
+  }
+
+  protected Sdk getTestProjectSdk() {
+    Sdk sdk = IdeaTestUtil.getMockJdk17();
+    LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_5);
+    return sdk;
+  }
+
+  @Override
+  @NonNls
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath() + "/inspection/";
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/LightCodeInsightTestCase.java b/java/testFramework/src/com/intellij/testFramework/LightCodeInsightTestCase.java
new file mode 100644
index 0000000..0ecf5ff
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/LightCodeInsightTestCase.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+
+/**
+ * A TestCase for single PsiFile being opened in Editor conversion. See configureXXX and checkResultXXX method docs.
+ */
+public abstract class LightCodeInsightTestCase extends LightPlatformCodeInsightTestCase {
+  private LanguageLevel myOldLanguageLevel;
+
+  @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
+  protected LightCodeInsightTestCase() {
+    IdeaTestCase.initPlatformPrefix();
+  }
+
+  public static JavaPsiFacadeEx getJavaFacade() {
+    return JavaPsiFacadeEx.getInstanceEx(ourProject);
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myOldLanguageLevel = LanguageLevelProjectExtension.getInstance(getProject()).getLanguageLevel();
+    setLanguageLevel(getLanguageLevel());
+  }
+
+  protected LanguageLevel getLanguageLevel() {
+    return LanguageLevel.HIGHEST;
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    setLanguageLevel(myOldLanguageLevel);
+    super.tearDown();
+  }
+
+  protected static void setLanguageLevel(final LanguageLevel level) {
+    LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(level);
+  }
+
+  @Override
+  protected Sdk getProjectJDK() {
+    return IdeaTestUtil.getMockJdk17();
+  }
+
+  @Override
+  protected ModuleType getModuleType() {
+    return StdModuleTypes.JAVA;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/LightIdeaTestCase.java b/java/testFramework/src/com/intellij/testFramework/LightIdeaTestCase.java
new file mode 100644
index 0000000..8da3a59
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/LightIdeaTestCase.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+
+/**
+ * A test case that provides IDEA application and project. Note both are reused for each test run in the session so
+ * be careful to return all the modification made to application and project components (such as settings) after
+ * test is finished so other test aren't affected. The project is initialized with single module that have single
+ * content and source entry. For your convenience the project may be equipped with some mock JDK so your tests may
+ * refer to external classes. In order to enable this feature you have to have a folder named "mockJDK" under
+ * idea installation home that is used for test running. Place src.zip under that folder. We'd suggest this is real mock
+ * so it contains classes that is really needed in order to speed up tests startup.
+ */
+public abstract class LightIdeaTestCase extends LightPlatformTestCase {
+  @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
+  public LightIdeaTestCase() {
+    IdeaTestCase.initPlatformPrefix();
+  }
+
+  public static JavaPsiFacadeEx getJavaFacade() {
+    return JavaPsiFacadeEx.getInstanceEx(ourProject);
+  }
+
+  @Override
+  protected Sdk getProjectJDK() {
+    return IdeaTestUtil.getMockJdk17();
+  }
+
+  @Override
+  protected ModuleType getModuleType() {
+    return StdModuleTypes.JAVA;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java
new file mode 100644
index 0000000..e91b5ff
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/ModuleTestCase.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.ide.highlighter.ModuleFileType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.module.impl.ModuleImpl;
+import com.intellij.openapi.project.impl.ProjectImpl;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.impl.ModuleRootManagerImpl;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileVisitor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public abstract class ModuleTestCase extends IdeaTestCase {
+  protected final Collection<Module> myModulesToDispose = new ArrayList<Module>();
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myModulesToDispose.clear();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    try {
+      final ModuleManager moduleManager = ModuleManager.getInstance(myProject);
+      ApplicationManager.getApplication().runWriteAction(new Runnable() {
+        @Override
+        public void run() {
+          for (Module module : myModulesToDispose) {
+            String moduleName = module.getName();
+            if (moduleManager.findModuleByName(moduleName) != null) {
+              moduleManager.disposeModule(module);
+            }
+          }
+        }
+      });
+    }
+    finally {
+      myModulesToDispose.clear();
+      super.tearDown();
+    }
+  }
+
+  protected Module createModule(final File moduleFile) {
+    return createModule(moduleFile, StdModuleTypes.JAVA);
+  }
+
+  protected Module createModule(final File moduleFile, final ModuleType moduleType) {
+    final String path = moduleFile.getAbsolutePath();
+    return createModule(path, moduleType);
+  }
+
+  protected Module createModule(final String path, final ModuleType moduleType) {
+    Module module = ApplicationManager.getApplication().runWriteAction(
+      new Computable<Module>() {
+        @Override
+        public Module compute() {
+          return ModuleManager.getInstance(myProject).newModule(path, moduleType.getId());
+        }
+      }
+    );
+
+    myModulesToDispose.add(module);
+    return module;
+  }
+
+  protected Module loadModule(final File moduleFile) {
+    Module module = ApplicationManager.getApplication().runWriteAction(
+      new Computable<Module>() {
+        @Override
+        public Module compute() {
+          try {
+            return ModuleManager.getInstance(myProject).loadModule(moduleFile.getAbsolutePath());
+          }
+          catch (Exception e) {
+            LOG.error(e);
+            return null;
+          }
+        }
+      }
+    );
+
+    myModulesToDispose.add(module);
+    return module;
+  }
+
+  protected Module loadModule(final String modulePath) {
+    return loadModule(new File(modulePath));
+  }
+
+  @Nullable
+  protected Module loadAllModulesUnder(@NotNull VirtualFile rootDir) throws Exception {
+    final Ref<Module> result = Ref.create();
+
+    VfsUtilCore.visitChildrenRecursively(rootDir, new VirtualFileVisitor() {
+      @Override
+      public boolean visitFile(@NotNull VirtualFile file) {
+        if (!file.isDirectory() && file.getName().endsWith(ModuleFileType.DOT_DEFAULT_EXTENSION)) {
+          ModuleImpl module = (ModuleImpl)loadModule(new File(file.getPath()));
+          readJdomExternalizables(module);
+          result.setIfNull(module);
+        }
+        return true;
+      }
+    });
+
+    return result.get();
+  }
+
+  protected void readJdomExternalizables(final ModuleImpl module) {
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        final ProjectImpl project = (ProjectImpl)myProject;
+        project.setOptimiseTestLoadSpeed(false);
+        final ModuleRootManagerImpl moduleRootManager = (ModuleRootManagerImpl)ModuleRootManager.getInstance(module);
+        module.getStateStore().initComponent(moduleRootManager, false);
+        project.setOptimiseTestLoadSpeed(true);
+      }
+    });
+  }
+
+  protected Module createModuleFromTestData(final String dirInTestData, final String newModuleFileName, final ModuleType moduleType,
+                                            final boolean addSourceRoot)
+    throws IOException {
+    final File dirInTestDataFile = new File(dirInTestData);
+    assertTrue(dirInTestDataFile.isDirectory());
+    final File moduleDir = createTempDirectory();
+    FileUtil.copyDir(dirInTestDataFile, moduleDir);
+    final Module module = createModule(moduleDir + "/" + newModuleFileName, moduleType);
+    final VirtualFile root = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(moduleDir);
+    new WriteCommandAction.Simple(module.getProject()) {
+      @Override
+      protected void run() throws Throwable {
+        root.refresh(false, true);
+      }
+    }.execute().throwException();
+    if (addSourceRoot) {
+      PsiTestUtil.addSourceContentToRoots(module, root);
+    }
+    else {
+      PsiTestUtil.addContentRoot(module, root);
+    }
+    return module;
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java
new file mode 100644
index 0000000..63bbdb2
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/PsiTestCase.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.PsiManagerImpl;
+import com.intellij.util.IncorrectOperationException;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * @author Mike
+ */
+public abstract class PsiTestCase extends ModuleTestCase {
+  protected PsiManagerImpl myPsiManager;
+  protected PsiFile myFile;
+  protected PsiTestData myTestDataBefore;
+  protected PsiTestData myTestDataAfter;
+  private String myDataRoot;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myPsiManager = (PsiManagerImpl) PsiManager.getInstance(myProject);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    myPsiManager = null;
+    myFile = null;
+    myTestDataBefore = null;
+    myTestDataAfter = null;
+    super.tearDown();
+  }
+
+  protected PsiFile createDummyFile(String fileName, String text) throws IncorrectOperationException {
+    FileType type = FileTypeRegistry.getInstance().getFileTypeByFileName(fileName);
+    return PsiFileFactory.getInstance(myProject).createFileFromText(fileName, type, text);
+  }
+
+  protected PsiFile createFile(@NonNls String fileName, String text) throws Exception {
+    return createFile(myModule, fileName, text);
+  }
+  protected PsiFile createFile(Module module, String fileName, String text) throws Exception {
+    File dir = createTempDirectory();
+    VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/'));
+
+    return createFile(module, vDir, fileName, text);
+  }
+
+  protected PsiFile createFile(final Module module, final VirtualFile vDir, final String fileName, final String text) throws IOException {
+    return new WriteAction<PsiFile>() {
+      @Override
+      protected void run(Result<PsiFile> result) throws Throwable {
+        if (!ModuleRootManager.getInstance(module).getFileIndex().isInSourceContent(vDir)) {
+          addSourceContentToRoots(module, vDir);
+        }
+
+        final VirtualFile vFile = vDir.createChildData(vDir, fileName);
+        VfsUtil.saveText(vFile, text);
+        assertNotNull(vFile);
+        final PsiFile file = myPsiManager.findFile(vFile);
+        assertNotNull(file);
+        result.setResult(file);
+      }
+    }.execute().getResultObject();
+  }
+
+  protected void addSourceContentToRoots(final Module module, final VirtualFile vDir) {
+    PsiTestUtil.addSourceContentToRoots(module, vDir);
+  }
+
+  protected PsiElement configureByFileWithMarker(String filePath, String marker) throws Exception{
+    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(filePath.replace(File.separatorChar, '/'));
+    assertNotNull("file " + filePath + " not found", vFile);
+
+    String fileText = VfsUtil.loadText(vFile);
+    fileText = StringUtil.convertLineSeparators(fileText);
+
+    int offset = fileText.indexOf(marker);
+    assertTrue(offset >= 0);
+    fileText = fileText.substring(0, offset) + fileText.substring(offset + marker.length());
+
+    myFile = createFile(vFile.getName(), fileText);
+
+    return myFile.findElementAt(offset);
+  }
+
+  protected void configure(String path, String dataName) throws Exception {
+    myDataRoot = getTestDataPath() + path;
+
+    myTestDataBefore = loadData(dataName);
+
+    PsiTestUtil.removeAllRoots(myModule, IdeaTestUtil.getMockJdk17());
+    VirtualFile vDir = PsiTestUtil.createTestProjectStructure(myProject, myModule, myDataRoot, myFilesToDelete);
+
+    final VirtualFile vFile = vDir.findChild(myTestDataBefore.getTextFile());
+    myFile = myPsiManager.findFile(vFile);
+  }
+
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath();
+  }
+
+  protected String loadFile(String name) throws Exception {
+    String result = FileUtil.loadFile(new File(getTestDataPath() + File.separatorChar + name));
+    return StringUtil.convertLineSeparators(result);
+  }
+
+  private PsiTestData loadData(String dataName) throws Exception {
+    Document document = JDOMUtil.loadDocument(new File(myDataRoot + "/" + "data.xml"));
+
+    PsiTestData data = createData();
+    Element documentElement = document.getRootElement();
+
+    final List nodes = documentElement.getChildren("data");
+
+    for (Object node1 : nodes) {
+      Element node = (Element)node1;
+      String value = node.getAttributeValue("name");
+
+      if (value.equals(dataName)) {
+        DefaultJDOMExternalizer.readExternal(data, node);
+        data.loadText(myDataRoot);
+
+        return data;
+      }
+    }
+
+    throw new IllegalArgumentException("Cannot find data chunk '" + dataName + "'");
+  }
+
+  protected PsiTestData createData() {
+    return new PsiTestData();
+  }
+
+  protected void checkResult(String dataName) throws Exception {
+    myTestDataAfter = loadData(dataName);
+
+    final String textExpected = myTestDataAfter.getText();
+    final String actualText = myFile.getText();
+
+    if (!textExpected.equals(actualText)) {
+      System.out.println("Text mismatch: " + getName() + "(" + getClass().getName() + ")");
+      System.out.println("Text expected:");
+      printText(textExpected);
+      System.out.println("Text found:");
+      printText(actualText);
+
+      fail("text");
+    }
+
+//    assertEquals(myTestDataAfter.getText(), myFile.getText());
+  }
+
+  protected static void printText(String text) {
+    final String q = "\"";
+    System.out.print(q);
+
+    text = StringUtil.convertLineSeparators(text);
+
+    StringTokenizer tokenizer = new StringTokenizer(text, "\n", true);
+    while (tokenizer.hasMoreTokens()) {
+      final String token = tokenizer.nextToken();
+
+      if (token.equals("\n")) {
+        System.out.print(q);
+        System.out.println();
+        System.out.print(q);
+        continue;
+      }
+
+      System.out.print(token);
+    }
+
+    System.out.print(q);
+    System.out.println();
+  }
+
+  protected void addLibraryToRoots(final VirtualFile jarFile, OrderRootType rootType) {
+    addLibraryToRoots(myModule, jarFile, rootType);
+  }
+
+  protected static void addLibraryToRoots(final Module module, final VirtualFile root, final OrderRootType rootType) {
+    assertEquals(OrderRootType.CLASSES, rootType);
+    ModuleRootModificationUtil.addModuleLibrary(module, root.getUrl());
+  }
+
+
+  public PsiFile getFile() {
+    return myFile;
+  }
+
+  public com.intellij.openapi.editor.Document getDocument(PsiFile file) {
+    return PsiDocumentManager.getInstance(getProject()).getDocument(file);
+  }
+
+  public com.intellij.openapi.editor.Document getDocument(VirtualFile file) {
+    return FileDocumentManager.getInstance().getDocument(file);
+  }
+
+  public void commitDocument(com.intellij.openapi.editor.Document document) {
+    PsiDocumentManager.getInstance(getProject()).commitDocument(document);
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/PsiTestData.java b/java/testFramework/src/com/intellij/testFramework/PsiTestData.java
new file mode 100644
index 0000000..2691de2
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/PsiTestData.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jdom.Element;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author Mike
+ */
+public class PsiTestData implements JDOMExternalizable {
+  public String TEXT_FILE = "";
+  private String myText;
+
+  public String getTextFile() {
+    return TEXT_FILE;
+  }
+
+  public String getText() {
+    return myText;
+  }
+
+  public void loadText(String root) throws IOException{
+    String fileName = root + "/" + TEXT_FILE;
+    myText = FileUtil.loadFile(new File(fileName));
+    myText = StringUtil.convertLineSeparators(myText);
+  }
+
+  @Override
+  public void readExternal(Element element) throws InvalidDataException {
+    DefaultJDOMExternalizer.readExternal(this, element);
+  }
+
+  @Override
+  public void writeExternal(Element element) throws WriteExternalException {
+    DefaultJDOMExternalizer.writeExternal(this, element);
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java b/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java
new file mode 100644
index 0000000..e2cebe4
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/ResolveTestCase.java
@@ -0,0 +1,70 @@
+
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiReference;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+
+public abstract class ResolveTestCase extends PsiTestCase {
+  @NonNls protected static final String MARKER = "<ref>";
+
+  protected PsiReference configureByFile(@NonNls String filePath) throws Exception{
+    return configureByFile(filePath, null);
+  }
+  
+  protected PsiReference configureByFile(@TestDataFile @NonNls String filePath, @Nullable VirtualFile parentDir) throws Exception{
+    final String fullPath = getTestDataPath() + filePath;
+    final VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(fullPath.replace(File.separatorChar, '/'));
+    assertNotNull("file " + filePath + " not found", vFile);
+
+    String fileText = StringUtil.convertLineSeparators(VfsUtil.loadText(vFile));
+
+    final String fileName = vFile.getName();
+
+    return configureByFileText(fileText, fileName, parentDir);
+  }
+
+  protected PsiReference configureByFileText(String fileText, String fileName) throws Exception {
+    return configureByFileText(fileText, fileName, null);
+  }
+  
+  protected PsiReference configureByFileText(String fileText, String fileName, @Nullable final VirtualFile parentDir) throws Exception {
+    int offset = fileText.indexOf(MARKER);
+    assertTrue(offset >= 0);
+    fileText = fileText.substring(0, offset) + fileText.substring(offset + MARKER.length());
+
+    myFile = parentDir == null? createFile(myModule, fileName, fileText) : createFile(myModule, parentDir, fileName, fileText);
+    PsiReference ref = myFile.findReferenceAt(offset);
+
+    assertNotNull(ref);
+
+    return ref;
+  }
+
+  @Override
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath() + "/psi/resolve/";
+  }
+}
\ No newline at end of file
diff --git a/java/testFramework/src/com/intellij/testFramework/TestSourceBasedTestCase.java b/java/testFramework/src/com/intellij/testFramework/TestSourceBasedTestCase.java
new file mode 100644
index 0000000..377de5d
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/TestSourceBasedTestCase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework;
+
+import com.intellij.ide.highlighter.ProjectFileType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ex.PathManagerEx;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+
+@SuppressWarnings({"HardCodedStringLiteral", "ConstantConditions", "JUnitTestCaseInProductSource"})
+@NonNls public abstract class TestSourceBasedTestCase extends IdeaTestCase {
+  private File myTempDirectory;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    myTempDirectory = FileUtil.createTempDirectory(getTestName(true), "test",false);
+    myFilesToDelete.add(myTempDirectory);
+    final File testRoot = new File(getTestDataPath(), getTestPath());
+    assertTrue(testRoot.getAbsolutePath(), testRoot.isDirectory());
+
+    final File currentTestRoot = new File(testRoot, getTestDirectoryName());
+    assertTrue(currentTestRoot.getAbsolutePath(), currentTestRoot.isDirectory());
+
+    FileUtil.copyDir(currentTestRoot, new File(myTempDirectory, getTestDirectoryName()));
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+                                                             @Override
+                                                             public void run() {
+                                                               setupContentRoot();
+                                                             }
+                                                           });
+
+  }
+
+  protected String getTestDataPath() {
+    return PathManagerEx.getTestDataPath(getClass());
+  }
+
+  protected abstract String getTestPath();
+
+  private File getTestContentFile() {
+    return new File(myTempDirectory, getTestDirectoryName());
+  }
+
+  private void setupContentRoot() {
+    PsiTestUtil.addContentRoot(myModule, getContentRoot());
+    VirtualFile src = getContentRoot().findChild("src");
+    if (src != null) {
+      PsiTestUtil.addSourceRoot(myModule, src);
+    }
+  }
+
+  protected VirtualFile getContentRoot() {
+    File file = getTestContentFile();
+    return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
+  }
+
+  @Override
+  protected String getTestDirectoryName() {
+    return getTestName(true);
+  }
+
+
+  protected PsiDirectory getPackageDirectory(final String packageRelativePath) {
+    return getPsiManager().findDirectory(getContentRoot().findFileByRelativePath("src/" + packageRelativePath));
+  }
+
+  protected PsiDirectory getSrcDirectory() {
+    return getPsiManager().findDirectory(getContentRoot().findFileByRelativePath("src"));
+  }
+
+  protected PsiDirectory getContentDirectory() {
+    return getPsiManager().findDirectory(getContentRoot());
+  }
+  
+  protected String getRootFiles() {
+    return " " + myModule.getModuleFile().getName() + "\n" +
+           " " + myProject.getName() + ProjectFileType.DOT_DEFAULT_EXTENSION +
+           "\n";
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/builders/JavaModuleFixtureBuilder.java b/java/testFramework/src/com/intellij/testFramework/builders/JavaModuleFixtureBuilder.java
new file mode 100644
index 0000000..df0b9f2
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/builders/JavaModuleFixtureBuilder.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.testFramework.builders;
+
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.testFramework.fixtures.ModuleFixture;
+import org.jetbrains.annotations.NonNls;
+
+import java.util.Map;
+
+/**
+ * @author mike
+ */
+public interface JavaModuleFixtureBuilder<T extends ModuleFixture> extends ModuleFixtureBuilder<T> {
+
+  enum MockJdkLevel {
+    jdk14,
+    jdk15
+  }
+
+  JavaModuleFixtureBuilder setLanguageLevel(LanguageLevel languageLevel);
+
+  JavaModuleFixtureBuilder addLibrary(@NonNls String libraryName, @NonNls String... classPath);
+
+  JavaModuleFixtureBuilder addLibrary(@NonNls String libraryName, Map<OrderRootType, String[]> roots);
+
+  JavaModuleFixtureBuilder addLibraryJars(@NonNls String libraryName, @NonNls String basePath, @NonNls String... jarNames);
+
+  JavaModuleFixtureBuilder addJdk(@NonNls String jdkPath);
+
+  void setMockJdkLevel(MockJdkLevel level);
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/codeInsight/hierarchy/HierarchyViewTestBase.java b/java/testFramework/src/com/intellij/testFramework/codeInsight/hierarchy/HierarchyViewTestBase.java
new file mode 100755
index 0000000..5e6a31f
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/codeInsight/hierarchy/HierarchyViewTestBase.java
@@ -0,0 +1,155 @@
+package com.intellij.testFramework.codeInsight.hierarchy;
+
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Checks tree structure for Type Hierarchy (Ctrl+H), Call Hierarchy (Ctrl+Alt+H), Method Hierarchy (Ctrl+Shift+H).
+ */
+public abstract class HierarchyViewTestBase extends CodeInsightTestCase {
+
+  private static final String NODE_ELEMENT_NAME = "node";
+  private static final String ANY_NODES_ELEMENT_NAME = "any";
+  private static final String TEXT_ATTR_NAME = "text";
+  private static final String BASE_ATTR_NAME = "base";
+
+  protected abstract String getBasePath();
+
+  protected void doHierarchyTest(final Computable<HierarchyTreeStructure> treeStructureComputable, final String... fileNames)
+    throws Exception {
+    final String[] relFilePaths = new String[fileNames.length];
+    for (int i = 0; i < fileNames.length; i++) {
+      relFilePaths[i] = "/" + getBasePath() + "/" + fileNames[i];
+    }
+    configureByFiles(null, relFilePaths);
+
+    final String verificationFilePath = getTestDataPath() + "/" + getBasePath() + "/" + getTestName(false) + "_verification.xml";
+    HierarchyTreeStructure structure = treeStructureComputable.compute();
+    try {
+      checkHierarchyTreeStructure(structure, JDOMUtil.loadDocument(new File(verificationFilePath)));
+    } catch (Throwable e)  {
+      assertEquals("XML structure comparison for your convenience, actual failure details BELOW",
+                   FileUtil.loadFile(new File(verificationFilePath)), dump(structure, null, 0));
+      //noinspection CallToPrintStackTrace
+      e.printStackTrace();
+    }
+  }
+
+  private static String dump(final HierarchyTreeStructure treeStructure, @Nullable HierarchyNodeDescriptor descriptor, int level) {
+    StringBuilder s = new StringBuilder();
+    dump(treeStructure, descriptor, level, s);
+    return s.toString();
+  }
+
+  private static void dump(final HierarchyTreeStructure treeStructure,
+                             @Nullable HierarchyNodeDescriptor descriptor,
+                             int level,
+                             StringBuilder b) {
+    if (level > 10) {
+      for(int i = 0; i<level; i++) b.append("  ");
+      b.append("<Probably infinite part skipped>\n");
+      return;
+    }
+    if(descriptor==null) descriptor = (HierarchyNodeDescriptor)treeStructure.getRootElement();
+    for(int i = 0; i<level; i++) b.append("  ");
+    descriptor.update();
+    b.append("<node text=\"").append(descriptor.getHighlightedText().getText()).append("\"")
+      .append(treeStructure.getBaseDescriptor() == descriptor ? " base=\"true\"" : "");
+
+    final Object[] children = treeStructure.getChildElements(descriptor);
+    if(children.length>0) {
+      b.append(">\n");
+      for (Object o : children) {
+        HierarchyNodeDescriptor d = (HierarchyNodeDescriptor)o;
+        dump(treeStructure, d, level + 1, b);
+      }
+      for(int i = 0; i<level; i++) b.append("  ");
+      b.append("</node>\n");
+    } else {
+      b.append("/>\n");
+    }
+  }
+
+  private static void checkHierarchyTreeStructure(final HierarchyTreeStructure treeStructure, final Document document) {
+    final HierarchyNodeDescriptor rootNodeDescriptor = (HierarchyNodeDescriptor)treeStructure.getRootElement();
+    rootNodeDescriptor.update();
+    final Element rootElement = document.getRootElement();
+    if (rootElement == null || !NODE_ELEMENT_NAME.equals(rootElement.getName())) {
+      throw new IllegalArgumentException("Incorrect root element in verification resource");
+    }
+    checkNodeDescriptorRecursively(treeStructure, rootNodeDescriptor, rootElement);
+  }
+
+  private static void checkNodeDescriptorRecursively(final HierarchyTreeStructure treeStructure,
+                                                     final HierarchyNodeDescriptor descriptor,
+                                                     final Element expectedElement) {
+    checkBaseNode(treeStructure, descriptor, expectedElement);
+    checkContent(descriptor, expectedElement);
+    checkChildren(treeStructure, descriptor, expectedElement);
+  }
+
+  private static void checkBaseNode(final HierarchyTreeStructure treeStructure,
+                                    final HierarchyNodeDescriptor descriptor,
+                                    final Element expectedElement) {
+    final String baseAttrValue = expectedElement.getAttributeValue(BASE_ATTR_NAME);
+    final HierarchyNodeDescriptor baseDescriptor = treeStructure.getBaseDescriptor();
+    final boolean mustBeBase = "true".equalsIgnoreCase(baseAttrValue);
+    assertTrue("Incorrect base node", mustBeBase ? baseDescriptor == descriptor : baseDescriptor != descriptor);
+  }
+
+  private static void checkContent(final HierarchyNodeDescriptor descriptor, final Element expectedElement) {
+    assertEquals(expectedElement.getAttributeValue(TEXT_ATTR_NAME), descriptor.getHighlightedText().getText());
+  }
+
+  private static void checkChildren(final HierarchyTreeStructure treeStructure,
+                                    final HierarchyNodeDescriptor descriptor,
+                                    final Element element) {
+    if (element.getChild(ANY_NODES_ELEMENT_NAME) != null) {
+      return;
+    }
+
+    final Object[] children = treeStructure.getChildElements(descriptor);
+    //noinspection unchecked
+    final List<Element> expectedChildren = new ArrayList<Element>(element.getChildren(NODE_ELEMENT_NAME));
+
+    final StringBuilder messageBuilder = new StringBuilder("Actual children of [" + descriptor.getHighlightedText().getText() + "]:\n");
+    for (Object child : children) {
+      final HierarchyNodeDescriptor nodeDescriptor = (HierarchyNodeDescriptor)child;
+      nodeDescriptor.update();
+      messageBuilder.append("    [").append(nodeDescriptor.getHighlightedText().getText()).append("]\n");
+    }
+    assertEquals(messageBuilder.toString(), expectedChildren.size(), children.length);
+
+    Arrays.sort(children, new Comparator<Object>() {
+      @Override
+      public int compare(final Object first, final Object second) {
+        return ((HierarchyNodeDescriptor)first).getHighlightedText().getText()
+          .compareTo(((HierarchyNodeDescriptor)second).getHighlightedText().getText());
+      }
+    });
+
+    Collections.sort(expectedChildren, new Comparator<Element>() {
+      @Override
+      public int compare(final Element first, final Element second) {
+        return first.getAttributeValue(TEXT_ATTR_NAME).compareTo(second.getAttributeValue(TEXT_ATTR_NAME));
+      }
+    });
+
+    //noinspection unchecked
+    final Iterator<Element> iterator = expectedChildren.iterator();
+    for (Object child : children) {
+      checkNodeDescriptorRecursively(treeStructure, ((HierarchyNodeDescriptor)child), iterator.next());
+    }
+  }
+
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/DefaultLightProjectDescriptor.java b/java/testFramework/src/com/intellij/testFramework/fixtures/DefaultLightProjectDescriptor.java
new file mode 100644
index 0000000..2a2d15c
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/DefaultLightProjectDescriptor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.LanguageLevelModuleExtension;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.testFramework.LightProjectDescriptor;
+
+/**
+* @author peter
+*/
+public class DefaultLightProjectDescriptor implements LightProjectDescriptor {
+  @Override
+  public ModuleType getModuleType() {
+    return StdModuleTypes.JAVA;
+  }
+
+  @Override
+  public Sdk getSdk() {
+    return IdeaTestUtil.getMockJdk17();
+  }
+
+  @Override
+  public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
+    LanguageLevelModuleExtension extension = model.getModuleExtension(LanguageLevelModuleExtension.class);
+    if (extension != null) {
+      extension.setLanguageLevel(LanguageLevel.HIGHEST);
+    }
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java
new file mode 100644
index 0000000..d811f49
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightFixtureTestCase.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElementFactory;
+import com.intellij.psi.PsiManager;
+import com.intellij.testFramework.IdeaTestCase;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+
+/**
+ * @author peter
+ */
+public abstract class JavaCodeInsightFixtureTestCase extends UsefulTestCase{
+  protected JavaCodeInsightTestFixture myFixture;
+  protected Module myModule;
+
+  @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors"})
+  protected JavaCodeInsightFixtureTestCase() {
+    IdeaTestCase.initPlatformPrefix();
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    final TestFixtureBuilder<IdeaProjectTestFixture> projectBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(getName());
+    myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(projectBuilder.getFixture());
+    final JavaModuleFixtureBuilder moduleFixtureBuilder = projectBuilder.addModule(JavaModuleFixtureBuilder.class);
+    moduleFixtureBuilder.addSourceContentRoot(myFixture.getTempDirPath());
+    tuneFixture(moduleFixtureBuilder);    
+
+    myFixture.setUp();
+    myFixture.setTestDataPath(getTestDataPath());
+    myModule = moduleFixtureBuilder.getFixture().getModule();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    myModule = null;
+    myFixture.tearDown();
+    myFixture = null;
+    super.tearDown();
+  }
+
+  /**
+   * Return relative path to the test data. Path is relative to the
+   * {@link com.intellij.openapi.application.PathManager#getHomePath()}
+   *
+   * @return relative path to the test data.
+   */
+  @NonNls
+  protected String getBasePath() {
+    return "";
+  }
+
+  /**
+   * Return absolute path to the test data. Not intended to be overridden.
+   *
+   * @return absolute path to the test data.
+   */
+  @NonNls
+  protected String getTestDataPath() {
+    return PathManager.getHomePath().replace(File.separatorChar, '/') + getBasePath();
+  }
+
+  protected void tuneFixture(final JavaModuleFixtureBuilder moduleBuilder) throws Exception {}
+
+
+  protected Project getProject() {
+    return myFixture.getProject();
+  }
+
+  protected PsiManager getPsiManager() {
+    return PsiManager.getInstance(getProject());
+  }
+
+  public PsiElementFactory getElementFactory() {
+    return JavaPsiFacade.getInstance(getProject()).getElementFactory();
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java
new file mode 100644
index 0000000..e5d8c43
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestFixture.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiPackage;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author yole
+ */
+public interface JavaCodeInsightTestFixture extends CodeInsightTestFixture {
+  JavaPsiFacadeEx getJavaFacade();
+
+  PsiClass addClass(@NotNull @NonNls final String classText);
+
+  @NotNull
+  PsiClass findClass(@NotNull @NonNls String name);
+
+  @NotNull
+  PsiPackage findPackage(@NotNull @NonNls String name);
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestUtil.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestUtil.java
new file mode 100644
index 0000000..dac9920
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaCodeInsightTestUtil.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.*;
+import com.intellij.refactoring.inline.InlineConstantFieldProcessor;
+import com.intellij.refactoring.inline.InlineLocalHandler;
+import com.intellij.refactoring.inline.InlineMethodProcessor;
+import com.intellij.refactoring.inline.InlineParameterHandler;
+import com.intellij.refactoring.util.InlineUtil;
+import org.jetbrains.annotations.NotNull;
+
+
+public class JavaCodeInsightTestUtil {
+  private static final int TARGET_FOR_INLINE_FLAGS =
+    TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED;
+
+  private JavaCodeInsightTestUtil() { }
+
+  public static void doInlineLocalTest(@NotNull final CodeInsightTestFixture fixture,
+                                       @NotNull final String before, @NotNull final String after) {
+    fixture.configureByFile(before);
+    new WriteCommandAction(fixture.getProject()) {
+      @Override
+      protected void run(final Result result) throws Throwable {
+        final Editor editor = fixture.getEditor();
+        final PsiElement element = TargetElementUtilBase.findTargetElement(editor, TARGET_FOR_INLINE_FLAGS);
+        assert element instanceof PsiLocalVariable : element;
+        InlineLocalHandler.invoke(fixture.getProject(), editor, (PsiLocalVariable)element, null);
+      }
+    }.execute();
+    fixture.checkResultByFile(after, false);
+  }
+
+  public static void doInlineParameterTest(@NotNull final CodeInsightTestFixture fixture,
+                                           @NotNull final String before, @NotNull final String after) {
+    fixture.configureByFile(before);
+    new WriteCommandAction(fixture.getProject()) {
+      @Override
+      protected void run(final Result result) throws Throwable {
+        final Editor editor = fixture.getEditor();
+        final PsiElement element = TargetElementUtilBase.findTargetElement(editor, TARGET_FOR_INLINE_FLAGS);
+        assert element instanceof PsiParameter : element;
+        new InlineParameterHandler().inlineElement(getProject(), editor, element);
+      }
+    }.execute();
+    fixture.checkResultByFile(after, false);
+  }
+
+  public static void doInlineMethodTest(@NotNull final CodeInsightTestFixture fixture,
+                                        @NotNull final String before, @NotNull final String after) {
+    fixture.configureByFile(before);
+    new WriteCommandAction(fixture.getProject()) {
+      @Override
+      protected void run(final Result result) throws Throwable {
+        final Editor editor = fixture.getEditor();
+        final PsiElement element = TargetElementUtilBase.findTargetElement(editor, TARGET_FOR_INLINE_FLAGS);
+        assert element instanceof PsiMethod : element;
+
+        final PsiReference ref = fixture.getFile().findReferenceAt(editor.getCaretModel().getOffset());
+        final PsiReferenceExpression refExpr = ref instanceof PsiReferenceExpression ? (PsiReferenceExpression)ref : null;
+
+        final PsiMethod method = (PsiMethod)element;
+        assert !(InlineMethodProcessor.checkBadReturns(method) && !InlineUtil.allUsagesAreTailCalls(method)) : "Bad returns found";
+        new InlineMethodProcessor(getProject(), method, refExpr, editor, false).run();
+      }
+    }.execute();
+    fixture.checkResultByFile(after, false);
+  }
+
+  public static void doInlineConstantTest(@NotNull final CodeInsightTestFixture fixture,
+                                          @NotNull final String before, @NotNull final String after) {
+    fixture.configureByFile(before);
+    new WriteCommandAction(fixture.getProject()) {
+      @Override
+      protected void run(final Result result) throws Throwable {
+        final Editor editor = fixture.getEditor();
+        final PsiElement element = TargetElementUtilBase.findTargetElement(editor, TARGET_FOR_INLINE_FLAGS);
+        assert element instanceof PsiField : element;
+
+        final PsiReference ref = fixture.getFile().findReferenceAt(editor.getCaretModel().getOffset());
+        final PsiReferenceExpression refExpr = ref instanceof PsiReferenceExpression ? (PsiReferenceExpression)ref : null;
+
+        new InlineConstantFieldProcessor((PsiField)element, getProject(), refExpr, false).run();
+      }
+    }.execute();
+    fixture.checkResultByFile(after, false);
+  }
+}
\ No newline at end of file
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java
new file mode 100644
index 0000000..5ae1917
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/JavaTestFixtureFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author yole
+ */
+public abstract class JavaTestFixtureFactory {
+  private static final JavaTestFixtureFactory ourInstance;
+
+  static {
+    try {
+      final Class<?> aClass = Class.forName("com.intellij.testFramework.fixtures.impl.JavaTestFixtureFactoryImpl");
+      ourInstance = (JavaTestFixtureFactory)aClass.newInstance();
+    }
+    catch (Exception e) {
+      throw new RuntimeException("Can't instantiate factory", e);
+    }
+  }
+
+  public static JavaTestFixtureFactory getFixtureFactory() {
+    return ourInstance;
+  }
+
+  public abstract TestFixtureBuilder<IdeaProjectTestFixture> createLightFixtureBuilder();
+
+  public abstract JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture);
+
+  public abstract JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture, TempDirTestFixture tempDirFixture);
+
+  /**
+   *
+   * @deprecated use {@link JavaTestFixtureFactory#createFixtureBuilder(String)}
+   */
+  //also implicitly initializes ourInstance and registers java module fixture builder
+  public static TestFixtureBuilder<IdeaProjectTestFixture> createFixtureBuilder() {
+    return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder();
+  }
+  public static TestFixtureBuilder<IdeaProjectTestFixture> createFixtureBuilder(@NotNull String name) {
+    return IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(name);
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java b/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java
new file mode 100644
index 0000000..4d284cf
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/LightCodeInsightFixtureTestCase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.LanguageLevelModuleExtension;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.*;
+import com.intellij.testFramework.*;
+import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+/**
+ * @author peter
+ */
+public abstract class LightCodeInsightFixtureTestCase extends UsefulTestCase{
+  public static final LightProjectDescriptor JAVA_1_6 = new DefaultLightProjectDescriptor() {
+    @Override
+    public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
+      model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_6);
+    }
+  };
+  public static final LightProjectDescriptor JAVA_LATEST = new DefaultLightProjectDescriptor();
+
+
+  protected JavaCodeInsightTestFixture myFixture;
+  protected Module myModule;
+
+  @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
+  protected LightCodeInsightFixtureTestCase() {
+    IdeaTestCase.initPlatformPrefix();
+  }
+
+  @SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
+  public LightCodeInsightFixtureTestCase(String classToTest, String prefix) {
+    PlatformTestCase.initPlatformPrefix(classToTest, prefix);
+  }
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
+    TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = factory.createLightFixtureBuilder(getProjectDescriptor());
+    final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture();
+    myFixture = JavaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture, new LightTempDirTestFixtureImpl(true));
+
+    myFixture.setUp();
+    myFixture.setTestDataPath(getTestDataPath());
+
+    myModule = myFixture.getModule();
+  }
+
+  /**
+   * Return relative path to the test data.
+   *
+   * @return relative path to the test data.
+   */
+  @NonNls
+  protected String getBasePath() {
+    return "";
+  }
+
+  @NotNull
+  protected LightProjectDescriptor getProjectDescriptor() {
+    return JAVA_LATEST;
+  }
+
+
+  /**
+   * Return absolute path to the test data. Not intended to be overridden.
+   *
+   * @return absolute path to the test data.
+   */
+  @NonNls
+  protected String getTestDataPath() {
+    String communityPath = PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/');
+    String path = communityPath + getBasePath();
+    if (new File(path).exists()) return path;
+    return communityPath + "/../" + getBasePath();
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    myFixture.tearDown();
+    myFixture = null;
+    myModule = null;
+    super.tearDown();
+  }
+  protected final void runTestBare() throws Throwable {
+    LightCodeInsightFixtureTestCase.super.runTest();
+  }
+
+  protected Project getProject() {
+    return myFixture.getProject();
+  }
+
+  protected PsiManager getPsiManager() {
+    return PsiManager.getInstance(getProject());
+  }
+
+  public PsiElementFactory getElementFactory() {
+    return JavaPsiFacade.getInstance(getProject()).getElementFactory();
+  }
+
+  protected PsiFile createLightFile(final FileType fileType, final String text) {
+    return PsiFileFactory.getInstance(getProject()).createFileFromText("a." + fileType.getDefaultExtension(), fileType, text);
+  }
+
+  public PsiFile createLightFile(final String fileName, final Language language, final String text) {
+    return PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, language, text, false, true);
+  }
+
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java
new file mode 100644
index 0000000..e4d075b
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaCodeInsightTestFixtureImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures.impl;
+
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.JavaPsiFacadeEx;
+import com.intellij.psi.impl.PsiModificationTrackerImpl;
+import com.intellij.psi.search.ProjectScope;
+import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
+import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author yole
+ */
+public class JavaCodeInsightTestFixtureImpl extends CodeInsightTestFixtureImpl implements JavaCodeInsightTestFixture {
+  public JavaCodeInsightTestFixtureImpl(IdeaProjectTestFixture projectFixture, TempDirTestFixture tempDirFixture) {
+    super(projectFixture, tempDirFixture);
+  }
+
+  @Override
+  public JavaPsiFacadeEx getJavaFacade() {
+    assertInitialized();
+    return JavaPsiFacadeEx.getInstanceEx(getProject());
+  }
+
+  @Override
+  public PsiClass addClass(@NotNull @NonNls final String classText) {
+    assertInitialized();
+    final PsiClass psiClass = addClass(getTempDirPath(), classText);
+    final VirtualFile file = psiClass.getContainingFile().getVirtualFile();
+    allowTreeAccessForFile(file);
+    return psiClass;
+  }
+
+  private PsiClass addClass(@NonNls final String rootPath, @NotNull @NonNls final String classText) {
+    final String qName =
+      ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+        public String compute() {
+          final PsiFileFactory factory = PsiFileFactory.getInstance(getProject());
+          final PsiJavaFile javaFile = (PsiJavaFile)factory.createFileFromText("a.java", JavaFileType.INSTANCE, classText);
+          return javaFile.getClasses()[0].getQualifiedName();
+        }
+      });
+    assert qName != null;
+    final PsiFile psiFile = addFileToProject(rootPath, qName.replace('.', '/') + ".java", classText);
+    return ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
+            public PsiClass compute() {
+              return ((PsiJavaFile)psiFile).getClasses()[0];
+            }
+          });
+  }
+
+  @Override
+  @NotNull
+  public PsiClass findClass(@NotNull @NonNls final String name) {
+    final PsiClass aClass = getJavaFacade().findClass(name, ProjectScope.getProjectScope(getProject()));
+    assertNotNull("Class " + name + " not found", aClass);
+    return aClass;
+  }
+
+  @Override
+  @NotNull
+  public PsiPackage findPackage(@NotNull @NonNls final String name) {
+    final PsiPackage aPackage = getJavaFacade().findPackage(name);
+    assertNotNull("Package " + name + " not found", aPackage);
+    return aPackage;
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    ((PsiModificationTrackerImpl)getPsiManager().getModificationTracker()).incCounter();// drop all caches
+    super.tearDown();
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java
new file mode 100644
index 0000000..21f3e43
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaModuleFixtureBuilderImpl.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.testFramework.fixtures.impl;
+
+import com.intellij.compiler.CompilerConfigurationImpl;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.MockJdkWrapper;
+import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
+import com.intellij.openapi.roots.*;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
+import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
+import com.intellij.testFramework.fixtures.ModuleFixture;
+import com.intellij.testFramework.fixtures.TestFixtureBuilder;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author mike
+ */
+abstract class JavaModuleFixtureBuilderImpl<T extends ModuleFixture> extends ModuleFixtureBuilderImpl<T> implements JavaModuleFixtureBuilder<T> {
+  private final List<Lib> myLibraries = new ArrayList<Lib>();
+  private String myJdk;
+  private MockJdkLevel myMockJdkLevel = MockJdkLevel.jdk14;
+  private LanguageLevel myLanguageLevel = null;
+
+  public JavaModuleFixtureBuilderImpl(final TestFixtureBuilder<? extends IdeaProjectTestFixture> fixtureBuilder) {
+    super(StdModuleTypes.JAVA, fixtureBuilder);
+  }
+
+  public JavaModuleFixtureBuilderImpl(final ModuleType moduleType, final TestFixtureBuilder<? extends IdeaProjectTestFixture> fixtureBuilder) {
+    super(moduleType, fixtureBuilder);
+  }
+
+  @Override
+  public JavaModuleFixtureBuilder setLanguageLevel(final LanguageLevel languageLevel) {
+    myLanguageLevel = languageLevel;
+    return this;
+  }
+
+  @Override
+  public JavaModuleFixtureBuilder addLibrary(String libraryName, String... classPath) {
+    final HashMap<OrderRootType, String[]> map = new HashMap<OrderRootType, String[]>();
+    for (String path : classPath) {
+      if (!new File(path).exists()) {
+        System.out.println(path + " not exists");
+      }
+    }
+    map.put(OrderRootType.CLASSES, classPath);
+    myLibraries.add(new Lib(libraryName, map));
+    return this;
+  }
+
+  @Override
+  public JavaModuleFixtureBuilder addLibrary(@NonNls final String libraryName, final Map<OrderRootType, String[]> roots) {
+    myLibraries.add(new Lib(libraryName, roots));
+    return this;
+  }
+
+  @Override
+  public JavaModuleFixtureBuilder addLibraryJars(String libraryName, String basePath, String... jars) {
+    if (!basePath.endsWith("/")) {
+      basePath += "/";
+    }
+    String[] classPath = ArrayUtil.newStringArray(jars.length);
+    for (int i = 0; i < jars.length; i++) {
+      classPath[i] = basePath + jars[i];
+    }
+    return addLibrary(libraryName, classPath);
+  }
+
+  @Override
+  public JavaModuleFixtureBuilder addJdk(String jdkPath) {
+    myJdk = jdkPath;
+    return this;
+  }
+
+  @Override
+  public void setMockJdkLevel(final MockJdkLevel level) {
+    myMockJdkLevel = level;
+  }
+
+  @Override
+  protected void initModule(final Module module) {
+    super.initModule(module);
+
+    final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
+    final LibraryTable libraryTable = model.getModuleLibraryTable();
+
+    for (Lib lib : myLibraries) {
+      String libraryName = lib.getName();
+
+      final Library library = libraryTable.createLibrary(libraryName);
+
+      final Library.ModifiableModel libraryModel = library.getModifiableModel();
+
+      for (OrderRootType rootType : OrderRootType.getAllTypes()) {
+        final String[] roots = lib.getRoots(rootType);
+        for (String root : roots) {
+          VirtualFile vRoot = LocalFileSystem.getInstance().refreshAndFindFileByPath(root);
+          if (vRoot != null && OrderRootType.CLASSES.equals(rootType) && !vRoot.isDirectory()) {
+            final VirtualFile jar = JarFileSystem.getInstance().refreshAndFindFileByPath(root + "!/");
+            if (jar != null) vRoot = jar;
+          }
+          if (vRoot != null) {
+            libraryModel.addRoot(vRoot, rootType);
+          }
+        }
+      }
+      libraryModel.commit();
+    }
+
+    final Sdk jdk;
+    if (myJdk != null) {
+      jdk = JavaSdk.getInstance().createJdk(module.getName() + "_jdk", myJdk, false);
+      ((ProjectJdkImpl)jdk).setVersionString("java 1.5");
+    }
+    else {
+      jdk = IdeaTestUtil.getMockJdk17();
+    }
+    if (jdk != null) {
+      model.setSdk(new MockJdkWrapper(CompilerConfigurationImpl.getTestsExternalCompilerHome(), jdk));
+    }
+
+    if (myLanguageLevel != null) {
+      model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLanguageLevel);
+    }
+    else if (myMockJdkLevel == MockJdkLevel.jdk15) {
+      model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_1_5);
+    }
+
+    model.commit();
+
+    for (OrderEntry entry : ModuleRootManager.getInstance(module).getOrderEntries()) {
+      if (entry instanceof LibraryOrderEntry) {
+        Library library = ((LibraryOrderEntry)entry).getLibrary();
+        libraryCreated(library, module);
+      }
+    }
+  }
+
+  @Override
+  protected void setupRootModel(ModifiableRootModel rootModel) {
+    if (myOutputPath != null) {
+      final File pathFile = new File(myOutputPath);
+      if (!pathFile.mkdirs()) {
+        assert pathFile.exists() : "unable to create: " + myOutputPath;
+      }
+      final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(myOutputPath);
+      assert virtualFile != null : "cannot find output path: " + myOutputPath;
+      rootModel.getModuleExtension(CompilerModuleExtension.class).setCompilerOutputPath(virtualFile);
+      rootModel.getModuleExtension(CompilerModuleExtension.class).inheritCompilerOutputPath(false);
+      rootModel.getModuleExtension(CompilerModuleExtension.class).setExcludeOutput(false);
+    }
+    if (myTestOutputPath != null) {
+      assert new File(myTestOutputPath).mkdirs() : myTestOutputPath;
+      final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(myTestOutputPath);
+      assert virtualFile != null : "cannot find test output path: " + myTestOutputPath;
+      rootModel.getModuleExtension(CompilerModuleExtension.class).setCompilerOutputPathForTests(virtualFile);
+      rootModel.getModuleExtension(CompilerModuleExtension.class).inheritCompilerOutputPath(false);
+      rootModel.getModuleExtension(CompilerModuleExtension.class).setExcludeOutput(false);
+    }
+  }
+
+  protected void libraryCreated(Library library, Module module) {}
+
+  private static class Lib {
+    private final String myName;
+    private final Map<OrderRootType, String []> myRoots;
+
+    public Lib(final String name, final Map<OrderRootType, String[]> roots) {
+      myName = name;
+      myRoots = roots;
+    }
+
+    public String getName() {
+      return myName;
+    }
+
+    public String [] getRoots(OrderRootType rootType) {
+      final String[] roots = myRoots.get(rootType);
+      return roots != null ? roots : ArrayUtil.EMPTY_STRING_ARRAY;
+    }
+  }
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java
new file mode 100644
index 0000000..d4e85df
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/fixtures/impl/JavaTestFixtureFactoryImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2009 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.testFramework.fixtures.impl;
+
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
+import com.intellij.testFramework.fixtures.*;
+
+/**
+ * @author yole
+ */
+public class JavaTestFixtureFactoryImpl extends JavaTestFixtureFactory {
+  public JavaTestFixtureFactoryImpl() {
+    IdeaTestFixtureFactory.getFixtureFactory().registerFixtureBuilder(JavaModuleFixtureBuilder.class, MyJavaModuleFixtureBuilderImpl.class);
+  }
+
+  @Override
+  public JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture) {
+    return new JavaCodeInsightTestFixtureImpl(projectFixture, new TempDirTestFixtureImpl());
+  }
+
+  @Override
+  public JavaCodeInsightTestFixture createCodeInsightFixture(IdeaProjectTestFixture projectFixture, TempDirTestFixture tempDirFixture) {
+    return new JavaCodeInsightTestFixtureImpl(projectFixture, tempDirFixture);
+  }
+
+  @Override
+  public TestFixtureBuilder<IdeaProjectTestFixture> createLightFixtureBuilder() {
+    return new LightTestFixtureBuilderImpl<IdeaProjectTestFixture>(new LightIdeaTestFixtureImpl(ourJavaProjectDescriptor));
+  }
+
+  public static class MyJavaModuleFixtureBuilderImpl extends JavaModuleFixtureBuilderImpl {
+    public MyJavaModuleFixtureBuilderImpl(final TestFixtureBuilder<? extends IdeaProjectTestFixture> testFixtureBuilder) {
+      super(testFixtureBuilder);
+    }
+
+    @Override
+    protected ModuleFixture instantiateFixture() {
+      return new ModuleFixtureImpl(this);
+    }
+  }
+
+  private static final LightProjectDescriptor ourJavaProjectDescriptor = LightCodeInsightFixtureTestCase.JAVA_1_6;
+}
diff --git a/java/testFramework/src/com/intellij/testFramework/package.html b/java/testFramework/src/com/intellij/testFramework/package.html
new file mode 100644
index 0000000..960f5c5
--- /dev/null
+++ b/java/testFramework/src/com/intellij/testFramework/package.html
@@ -0,0 +1,4 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html><body bgcolor="white">
+Provides a test framework for writing tests which use IDEA projects, PSI and other services.
+</body></html>
diff --git a/java/testFramework/testFramework-java.iml b/java/testFramework/testFramework-java.iml
new file mode 100644
index 0000000..408e30d
--- /dev/null
+++ b/java/testFramework/testFramework-java.iml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module relativePaths="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="openapi" exported="" />
+    <orderEntry type="module" module-name="util" exported="" />
+    <orderEntry type="library" name="JUnit4" level="project" />
+    <orderEntry type="library" name="JDOM" level="project" />
+    <orderEntry type="library" name="Log4J" level="project" />
+    <orderEntry type="module" module-name="lang-api" exported="" />
+    <orderEntry type="module" module-name="lang-impl" exported="" />
+    <orderEntry type="module" module-name="compiler-impl" />
+    <orderEntry type="module" module-name="java-impl" exported="" />
+    <orderEntry type="module" module-name="execution-impl" exported="" scope="RUNTIME" />
+    <orderEntry type="library" name="Groovy" level="project" />
+    <orderEntry type="module" module-name="testFramework" exported="" />
+    <orderEntry type="module" module-name="relaxng" exported="" scope="TEST" />
+    <orderEntry type="module" module-name="idea-ui" exported="" />
+  </component>
+  <component name="copyright">
+    <Base>
+      <setting name="state" value="1" />
+    </Base>
+  </component>
+</module>
+