Merge remote-tracking branch 'origin/master'

This commit is contained in:
Nadya Zabrodina
2015-04-16 14:48:47 +04:00
29 changed files with 1148 additions and 517 deletions
@@ -480,7 +480,7 @@ public class CompileDriver {
final Set<File> genSourceRoots = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
for (Module module : affectedModules) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
if (!module.isDisposed() && config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
genSourceRoots.add(new File(path));
@@ -78,7 +78,7 @@ public class CompilerPathsEx extends CompilerPaths {
public static String[] getOutputPaths(Module[] modules) {
final Set<String> outputPaths = new OrderedSet<String>();
for (Module module : modules) {
final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module);
final CompilerModuleExtension compilerModuleExtension = !module.isDisposed()? CompilerModuleExtension.getInstance(module) : null;
if (compilerModuleExtension == null) {
continue;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -212,6 +212,7 @@ public class TargetElementUtil extends TargetElementUtilBase {
return null;
}
@NotNull
@Override
public Collection<PsiElement> getTargetCandidates(final PsiReference reference) {
PsiElement parent = reference.getElement().getParent();
@@ -133,7 +133,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer, charTable, text,
originalTree, parentLightTree, 0);
originalTree, parentLightTree, null);
}
public PsiBuilderImpl(Project project,
@@ -145,7 +145,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree) {
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, 0);
this(project, containingFile, whiteSpaces, comments, lexer, charTable, text, originalTree, parentLightTree, null);
}
private PsiBuilderImpl(Project project,
@@ -157,7 +157,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final CharSequence text,
@Nullable ASTNode originalTree,
@Nullable MyTreeStructure parentLightTree,
int offset) {
LazyParseableToken parentToken) {
myProject = project;
myFile = containingFile;
@@ -170,9 +170,9 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myCharTable = charTable;
myOriginalTree = originalTree;
myParentLightTree = parentLightTree;
myOffset = offset;
myOffset = parentToken != null ? parentToken.getStartOffset() : 0;
cacheLexemes();
cacheLexemes(parentToken);
}
public PsiBuilderImpl(@NotNull final Project project,
@@ -190,10 +190,41 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
@NotNull final LighterLazyParseableNode chameleon,
@NotNull final CharSequence text) {
this(project, chameleon.getContainingFile(), parserDefinition.getWhitespaceTokens(), parserDefinition.getCommentTokens(), lexer,
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, chameleon.getStartOffset());
chameleon.getCharTable(), text, null, ((LazyParseableToken)chameleon).myParent, ((LazyParseableToken)chameleon)
);
}
private void cacheLexemes() {
private void cacheLexemes(LazyParseableToken parentToken) {
int[] lexStarts = null;
IElementType[] lexTypes = null;
int lexemeCount = -1;
boolean doLexingOptimizationCorrectionCheck = false;
if (parentToken != null) {
// there are two types of lazy parseable tokens out there: collapsed out of individual tokens or single token that needs to be expanded
// in first case parent PsiBuilder has all our text lexed so no need to do it again
int tokenCount = parentToken.myEndIndex - parentToken.myStartIndex;
if (tokenCount != 1) { // not expand single lazy parseable token case
lexStarts = new int[tokenCount + 1];
System.arraycopy(parentToken.myBuilder.myLexStarts, parentToken.myStartIndex, lexStarts, 0, tokenCount);
int diff = parentToken.myBuilder.myLexStarts[parentToken.myStartIndex];
for(int i = 0; i < tokenCount; ++i) lexStarts[i] -= diff;
lexStarts[tokenCount] = myText.length();
lexTypes = new IElementType[tokenCount];
System.arraycopy(parentToken.myBuilder.myLexTypes, parentToken.myStartIndex, lexTypes, 0, tokenCount);
lexemeCount = tokenCount;
}
ProgressIndicatorProvider.checkCanceled();
if (!doLexingOptimizationCorrectionCheck) {
myLexStarts = lexStarts;
myLexTypes = lexTypes;
myLexemeCount = lexemeCount;
return;
}
}
int approxLexCount = Math.max(10, myText.length() / 5);
myLexStarts = new int[approxLexCount];
@@ -216,7 +247,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
final IElementType tokenType = myLexer.getTokenType();
sb.append("Token sequence broken")
.append("\n this: '").append(myLexer.getTokenText()).append("' (").append(tokenType).append(':')
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":").append(myLexer.getTokenEnd());
.append(tokenType != null ? tokenType.getLanguage() : null).append(") ").append(tokenStart).append(":")
.append(myLexer.getTokenEnd());
if (i > 0) {
final int prevStart = myLexStarts[i - 1];
sb.append("\n prev: '").append(myText.subSequence(prevStart, offset)).append("' (").append(myLexTypes[i - 1]).append(':')
@@ -238,6 +270,19 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
myLexemeCount = i;
clearCachedTokenType();
//noinspection ConstantConditions
if (doLexingOptimizationCorrectionCheck) {
if (lexemeCount != -1) {
assert lexemeCount == myLexemeCount;
for(int j = 0; j < lexemeCount; ++j) {
if (myLexStarts[j] != lexStarts[j] || myLexTypes[j] != lexTypes[j]) {
assert false;
}
}
assert myLexStarts[lexemeCount] == lexStarts[lexemeCount];
}
}
}
@Override
@@ -1215,8 +1260,8 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
CharSequence context =
index < myLexStarts.length ? myText.subSequence(Math.max(0, myLexStarts[index] - 1000), myLexStarts[index]) : "<none>";
String language = myFile != null ? myFile.getLanguage() + ", " : "";
LOG.error(UNBALANCED_MESSAGE + "\n" +
"language: " + language + "\n" +
LOG.error(UNBALANCED_MESSAGE + "\n" +
"language: " + language + "\n" +
"context: '" + context + "'");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -336,10 +336,11 @@ public class TargetElementUtilBase {
}
}
@NotNull
public Collection<PsiElement> getTargetCandidates(PsiReference reference) {
if (reference instanceof PsiPolyVariantReference) {
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
final ArrayList<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
List<PsiElement> navigatableResults = new ArrayList<PsiElement>(results.length);
for(ResolveResult r:results) {
PsiElement element = r.getElement();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -558,7 +558,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
}
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, file, offset);
final PsiNameIdentifierOwner element = GotoDeclarationAction.findElementToShowUsagesOf(editor, offset);
if (element != null) {
PsiElement identifier = element.getNameIdentifier();
return new Info(identifier){
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,8 +83,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration");
if (elements.length != 1) {
if (elements.length == 0) {
PsiElement element = findElementToShowUsagesOf(editor, file, editor.getCaretModel().getOffset());
if (elements.length == 0 && suggestCandidates(TargetElementUtilBase.findReference(editor, offset)).isEmpty()) {
PsiElement element = findElementToShowUsagesOf(editor, editor.getCaretModel().getOffset());
if (element != null) {
ShowUsagesAction showUsages = (ShowUsagesAction)ActionManager.getInstance().getAction(ShowUsagesAction.ID);
RelativePoint popupPosition = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
@@ -111,7 +111,7 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
}
}
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, @NotNull PsiFile file, int offset) {
public static PsiNameIdentifierOwner findElementToShowUsagesOf(@NotNull Editor editor, int offset) {
PsiElement elementAt = TargetElementUtilBase.getInstance().findTargetElement(editor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED, offset);
if (elementAt instanceof PsiNameIdentifierOwner) {
return (PsiNameIdentifierOwner)elementAt;
@@ -184,7 +184,8 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code
return false;
}
private static Collection<PsiElement> suggestCandidates(final PsiReference reference) {
@NotNull
private static Collection<PsiElement> suggestCandidates(@Nullable PsiReference reference) {
if (reference == null) {
return Collections.emptyList();
}
@@ -325,12 +325,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
appendPairedInspectionsForUnfairTools(globalTools, globalSimpleTools, localTools);
((RefManagerImpl)getRefManager()).initializeAnnotators();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
runGlobalTools(scope, inspectionManager, globalTools);
}
});
runGlobalTools(scope, inspectionManager, globalTools);
if (runGlobalToolsOnly) return;
@@ -497,15 +492,16 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
return PsiDocumentManager.getInstance(getProject()).getDocument(file);
}
private void runGlobalTools(@NotNull AnalysisScope scope, @NotNull InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
private void runGlobalTools(@NotNull final AnalysisScope scope, @NotNull final InspectionManager inspectionManager, @NotNull List<Tools> globalTools) {
LOG.assertTrue(!ApplicationManager.getApplication().isReadAccessAllowed(), "Must not run under read action, too unresponsive");
final List<InspectionToolWrapper> needRepeatSearchRequest = new ArrayList<InspectionToolWrapper>();
final boolean surelyNoExternalUsages = scope.getScopeType() == AnalysisScope.PROJECT;
final boolean canBeExternalUsages = scope.getScopeType() != AnalysisScope.PROJECT;
for (Tools tools : globalTools) {
for (ScopeToolState state : tools.getTools()) {
InspectionToolWrapper toolWrapper = state.getTool();
GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
final InspectionToolWrapper toolWrapper = state.getTool();
final GlobalInspectionTool tool = (GlobalInspectionTool)toolWrapper.getTool();
final InspectionToolPresentation toolPresentation = getPresentation(toolWrapper);
try {
if (tool.isGraphNeeded()) {
try {
@@ -516,11 +512,17 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp
throw e;
}
}
tool.runInspection(scope, inspectionManager, this, toolPresentation);
//skip phase when we are sure that scope already contains everything
if (!surelyNoExternalUsages && tool.queryExternalUsagesRequests(inspectionManager, this, toolPresentation)) {
needRepeatSearchRequest.add(toolWrapper);
}
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
tool.runInspection(scope, inspectionManager, GlobalInspectionContextImpl.this, toolPresentation);
//skip phase when we are sure that scope already contains everything
if (canBeExternalUsages &&
tool.queryExternalUsagesRequests(inspectionManager, GlobalInspectionContextImpl.this, toolPresentation)) {
needRepeatSearchRequest.add(toolWrapper);
}
}
});
}
catch (ProcessCanceledException e) {
throw e;
+1
View File
@@ -157,6 +157,7 @@
<projectService
serviceInterface="git4idea.config.GitVcsSettings"
serviceImplementation="git4idea.config.GitVcsSettings"/>
<projectService serviceImplementation="git4idea.config.GitRebaseSettings"/>
<projectService serviceImplementation="git4idea.config.GitSharedSettings" />
<projectService
serviceInterface="git4idea.config.GitExecutableValidator"
@@ -17,16 +17,17 @@ package git4idea.actions;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitUtil;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitLineHandler;
import git4idea.commands.GitTask;
import git4idea.commands.GitTaskResult;
import git4idea.commands.GitTaskResultHandlerAdapter;
import git4idea.i18n.GitBundle;
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
import git4idea.rebase.GitRebaseEditorService;
@@ -50,7 +51,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
@NotNull final VirtualFile defaultRoot,
final Set<VirtualFile> affectedRoots,
final List<VcsException> exceptions) throws VcsException {
GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
final GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
if (h == null) {
return;
}
@@ -63,34 +64,32 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
affectedRoots.add(root);
service.configureHandler(h, editor.getHandlerNo());
GitTask task = new GitTask(project, h, GitBundle.getString("rebasing.title"));
task.executeInBackground(false, new GitTaskResultHandlerAdapter() {
new Task.Backgroundable(project, GitBundle.getString("rebasing.title"), false) {
@Override
protected void run(GitTaskResult taskResult) {
public void run(@NotNull ProgressIndicator indicator) {
AccessToken token = DvcsUtil.workingTreeChangeStarted(project);
try {
GitCommandResult result = ServiceManager.getService(Git.class).runCommand(h);
editor.close();
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
manager.updateRepository(root);
root.refresh(false, true);
notifyAboutResult(taskResult, resultListener, exceptions, project);
notifyAboutResult(result, resultListener, exceptions, project);
}
finally {
DvcsUtil.workingTreeChangeFinished(project, token);
}
}
});
}.queue();
}
private static void notifyAboutResult(GitTaskResult taskResult,
GitRebaseLineListener resultListener,
List<VcsException> exceptions,
Project project) {
if (taskResult == GitTaskResult.CANCELLED) {
return;
}
private static void notifyAboutResult(@NotNull GitCommandResult commandResult,
@NotNull GitRebaseLineListener resultListener,
@NotNull List<VcsException> exceptions,
@NotNull Project project) {
final GitRebaseLineListener.Result result = resultListener.getResult();
String messageId;
String message = null;
boolean isError = true;
switch (result.status) {
case CONFLICT:
@@ -98,6 +97,7 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
break;
case ERROR:
messageId = "rebase.result.error";
message = commandResult.getErrorOutputAsHtmlString();
break;
case CANCELLED:
// we do not need to show a message if editing was cancelled.
@@ -115,15 +115,9 @@ public abstract class GitRebaseActionBase extends GitRepositoryAction {
messageId = null;
}
String message;
String title;
if (messageId != null) {
String title = GitBundle.message(messageId + ".title");
if (message == null) {
message = GitBundle.message(messageId, result.current, result.total);
title = GitBundle.message(messageId + ".title");
}
else {
message = "Rebase finished: " + StringUtil.capitalize(StringUtil.toLowerCase(result.status.name()));
title = "";
}
if (isError) {
@@ -42,6 +42,14 @@ public interface Git {
@NotNull
GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor);
/**
* A generic method to run a Git command, when existing methods are not sufficient. <br/>
* Can be used instead of {@link #runCommand(Computable)} if the operation will not need to be repeated for sure
* (e.g. it is a completely local operation).
*/
@NotNull
GitCommandResult runCommand(@NotNull GitLineHandler handler);
@NotNull
GitCommandResult init(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLineHandlerListener... listeners);
@@ -47,6 +47,7 @@ import static java.util.Collections.singleton;
*
* @author Kirill Likhodedov
*/
@SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale")
public class GitImpl implements Git {
private final Logger LOG = Logger.getInstance(Git.class);
@@ -624,13 +625,24 @@ public class GitImpl implements Git {
public GitCommandResult runCommand(@NotNull Computable<GitLineHandler> handlerConstructor) {
return run(handlerConstructor);
}
@NotNull
@Override
public GitCommandResult runCommand(@NotNull final GitLineHandler handler) {
return runCommand(new Computable<GitLineHandler>() {
@Override
public GitLineHandler compute() {
return handler;
}
});
}
/**
* Check if the line looks line an error message
*/
private static boolean isError(String text) {
for (String indicator : ERROR_INDICATORS) {
if (text.startsWith(indicator.toLowerCase())) {
if (text.trim().toLowerCase().startsWith(indicator.toLowerCase())) {
return true;
}
}
@@ -640,7 +652,7 @@ public class GitImpl implements Git {
// could be upper-cased, so should check case-insensitively
public static final String[] ERROR_INDICATORS = {
"error", "remote: error", "fatal",
"Cannot apply", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
"Cannot", "Could not", "Interactive rebase already started", "refusing to pull", "cannot rebase:", "conflict",
"unable"
};
}
@@ -0,0 +1,89 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 git4idea.config;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import org.jetbrains.annotations.Nullable;
@State(name = "Git.Rebase.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class GitRebaseSettings implements PersistentStateComponent<GitRebaseSettings.State> {
private State myState = new State();
public static class State {
public boolean INTERACTIVE = true;
public boolean PRESERVE_MERGES = false;
public boolean SHOW_TAGS = false;
public boolean SHOW_REMOTE_BRANCHES = false;
public String ONTO = null;
}
@Nullable
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
public boolean isInteractive() {
return myState.INTERACTIVE;
}
public void setInteractive(boolean interactive) {
myState.INTERACTIVE = interactive;
}
public boolean isPreserveMerges() {
return myState.PRESERVE_MERGES;
}
public void setPreserveMerges(boolean preserveMerges) {
myState.PRESERVE_MERGES = preserveMerges;
}
public boolean showTags() {
return myState.SHOW_TAGS;
}
public void setShowTags(boolean showTags) {
myState.SHOW_TAGS = showTags;
}
public boolean showRemoteBranches() {
return myState.SHOW_REMOTE_BRANCHES;
}
public void setShowRemoteBranches(boolean showRemoteBranches) {
myState.SHOW_REMOTE_BRANCHES = showRemoteBranches;
}
@Nullable
public String getOnto() {
return myState.ONTO;
}
public void setOnto(@Nullable String onto) {
myState.ONTO = onto;
}
}
@@ -290,7 +290,6 @@ rebase.result.cancelled=The rebase process was cancelled.
rebase.result.conflict.title=Rebase Suspended
rebase.result.conflict=Stopped rebasing because of conflict ({0}/{1}).\nResolve conflicts and continue the rebase process.
rebase.result.error.title=Rebase Error
rebase.result.error=Stopped rebasing because of error while rebasing ({0}/{1}).\nCheck vcs console for details.
rebase.show.remote.branches.tooltip=If selected, remote branches are shown in drop down as well.
rebase.show.remote.branches=Show Re&mote Branches
rebase.show.tags.tooltip=Show tags in \"from\" and \"onto\" comboboxes.
@@ -15,10 +15,12 @@
*/
package git4idea.rebase;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
@@ -27,12 +29,15 @@ import git4idea.branch.GitBranchUtil;
import git4idea.commands.GitCommand;
import git4idea.commands.GitLineHandler;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitRebaseSettings;
import git4idea.i18n.GitBundle;
import git4idea.merge.GitMergeUtil;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.ui.GitReferenceValidator;
import git4idea.util.GitUIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
@@ -115,7 +120,7 @@ public class GitRebaseDialog extends DialogWrapper {
/**
* The current branch
*/
protected GitBranch myCurrentBranch;
@Nullable protected GitBranch myCurrentBranch;
/**
* The tags
*/
@@ -128,6 +133,9 @@ public class GitRebaseDialog extends DialogWrapper {
* The validator for from field
*/
private final GitReferenceValidator myFromValidator;
@NotNull private final GitRebaseSettings mySettings;
@Nullable private final String myOriginalOntoBranch;
/**
* A constructor
@@ -142,6 +150,7 @@ public class GitRebaseDialog extends DialogWrapper {
setOKButtonText(GitBundle.getString("rebase.button"));
init();
myProject = project;
mySettings = ServiceManager.getService(myProject, GitRebaseSettings.class);
final Runnable validateRunnable = new Runnable() {
public void run() {
validateFields();
@@ -157,11 +166,50 @@ public class GitRebaseDialog extends DialogWrapper {
validateFields();
}
});
setupBranches();
setupStrategy();
myInteractiveCheckBox.setSelected(mySettings.isInteractive());
myPreserveMergesCheckBox.setSelected(mySettings.isPreserveMerges());
myShowTagsCheckBox.setSelected(mySettings.showTags());
myShowRemoteBranchesCheckBox.setSelected(mySettings.showRemoteBranches());
overwriteOntoForCurrentBranch(mySettings);
myOriginalOntoBranch = GitUIUtil.getTextField(myOntoComboBox).getText();
validateFields();
}
@Nullable
@Override
public JComponent getPreferredFocusedComponent() {
return myOntoComboBox;
}
private void overwriteOntoForCurrentBranch(@NotNull GitRebaseSettings settings) {
String onto = settings.getOnto();
if (onto != null && !onto.equals(myBranchComboBox.getSelectedItem())) {
if (!isValidRevision(onto)) {
mySettings.setOnto(null);
}
else {
myOntoComboBox.setSelectedItem(onto);
}
}
}
private boolean isValidRevision(@NotNull String revisionExpression) {
try {
GitRevisionNumber.resolve(myProject, gitRoot(), revisionExpression);
return true;
}
catch (VcsException e) {
LOG.debug(e);
return false;
}
}
public GitLineHandler handler() {
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.REBASE);
h.setStdoutSuppressed(false);
@@ -195,6 +243,27 @@ public class GitRebaseDialog extends DialogWrapper {
return h;
}
@Override
protected void doOKAction() {
try {
rememberFields();
}
finally {
super.doOKAction();
}
}
private void rememberFields() {
mySettings.setInteractive(myInteractiveCheckBox.isSelected());
mySettings.setPreserveMerges(myPreserveMergesCheckBox.isSelected());
mySettings.setShowTags(myShowTagsCheckBox.isSelected());
mySettings.setShowRemoteBranches(myShowRemoteBranchesCheckBox.isSelected());
String onto = StringUtil.nullize(GitUIUtil.getTextField(myOntoComboBox).getText(), true);
if (onto != null && !onto.equals(myOriginalOntoBranch)) {
mySettings.setOnto(onto);
}
}
/**
* Setup strategy
*/
@@ -22,7 +22,9 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.Cell;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.TableSpeedSearch;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ListWithSelection;
@@ -132,6 +134,14 @@ public class GitRebaseEditor extends DialogWrapper {
actionColumn.setCellEditor(new DefaultCellEditor(editorComboBox));
actionColumn.setCellRenderer(ComboBoxTableCellRenderer.INSTANCE);
myCommitsTable.setDefaultRenderer(String.class, new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
append(value.toString());
SpeedSearchUtil.applySpeedSearchHighlighting(myCommitsTable, this, true, selected);
}
});
myCommitsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(final ListSelectionEvent e) {
myViewButton.setEnabled(myCommitsTable.getSelectedRowCount() == 1);
@@ -20,40 +20,31 @@
*/
package com.theoryinpractice.testng.configuration;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.testframework.SearchForTestsTask;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.model.IDEARemoteTestRunnerClient;
import com.theoryinpractice.testng.model.TestClassFilter;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.*;
import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class SearchingForTestsTask extends SearchForTestsTask {
private static final Logger LOG = Logger.getInstance("#" + SearchingForTestsTask.class.getName());
@@ -280,182 +271,9 @@ public class SearchingForTestsTask extends SearchForTestsTask {
protected void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiManager psiManager = PsiManager.getInstance(myProject);
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
final String packageName = data.getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
else if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
else if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
//it's a method
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
else if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
//for a group, we include all classes
PsiClass[] testClasses = TestNGUtil
.getAllTestClasses(new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true), false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(psiManager, className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myProject, true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
}
private void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(myConfig);
if (testObject != null) {
testObject.fillTestObjects(classes);
}
}
@@ -492,152 +310,4 @@ public class SearchingForTestsTask extends SearchForTestsTask {
return params;
}
private void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
private GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
}
@@ -29,7 +29,6 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit.RefactoringListeners;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
@@ -47,12 +46,12 @@ import com.intellij.refactoring.listeners.RefactoringElementAdapter;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import com.theoryinpractice.testng.model.TestType;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.testng.xml.Parser;
import java.util.*;
@@ -68,7 +67,7 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
public boolean ALTERNATIVE_JRE_PATH_ENABLED;
public String ALTERNATIVE_JRE_PATH;
private static final Object PARSE_LOCK = new Object();
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
public static final String DEFAULT_PACKAGE_CONFIGURATION_NAME = ExecutionBundle.message("default.package.configuration.name");
@@ -149,32 +148,14 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public String suggestedName() {
return data.getGeneratedName(getConfigurationModule());
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? testObject.getGeneratedName() : null;
}
@Override
public String getActionName() {
if (TestType.CLASS.getType().equals(data.TEST_OBJECT)) {
String shortName = JavaExecutionUtil.getShortClassName(data.MAIN_CLASS_NAME);
return ProgramRunnerUtil.shortenName(shortName, 0);
}
if (TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) {
String s = getName();
if (!isGeneratedName()) return '\"' + s + '\"';
if (data.getPackageName().trim().length() > 0) {
return "Tests in \"" + data.getPackageName() + '\"';
}
else {
return "All Tests";
}
}
if (TestType.METHOD.getType().equals(data.TEST_OBJECT)) {
return data.getMethodName() + "()";
}
if (TestType.SUITE.getType().equals(data.TEST_OBJECT)) {
return data.getSuiteName();
}
return data.getGroupName();
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
return testObject != null ? ProgramRunnerUtil.shortenName(testObject.getActionName(), 0) : null;
}
public void setVMParameters(String value) {
@@ -299,45 +280,9 @@ public class TestNGConfiguration extends ModuleBasedConfiguration<JavaRunConfigu
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
if (data.TEST_OBJECT.equals(TestType.CLASS.getType()) || data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
final SourceScope scope = data.getScope().getSourceScope(this);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
}
else if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
PsiPackage psiPackage = JavaPsiFacade.getInstance(project).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
else if (data.TEST_OBJECT.equals(TestType.SUITE.getType())) {
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
} else if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
final Set<String> patterns = data.getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
final TestNGTestObject testObject = TestNGTestObject.fromConfig(this);
if (testObject != null) {
testObject.checkConfiguration();
}
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), getConfigurationModule().getModule());
@@ -33,6 +33,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import org.testng.IDEATestNGRemoteListener;
public abstract class TestNGConfigurationProducer extends JavaRunConfigurationProducerBase<TestNGConfiguration> implements Cloneable {
@@ -58,7 +59,7 @@ public abstract class TestNGConfigurationProducer extends JavaRunConfigurationPr
String paramSetName = contextLocation instanceof PsiMemberParameterizedLocation
? getInvocationNumber(((PsiMemberParameterizedLocation)contextLocation).getParamSetName()) : null;
if (paramSetName != null && !Comparing.strEqual(paramSetName, testNGConfiguration.getProgramParameters())) return false;
TestData testobject = testNGConfiguration.getPersistantData();
TestNGTestObject testobject = TestNGTestObject.fromConfig(testNGConfiguration);
if (testobject != null) {
if (testobject.isConfiguredByElement(element)) {
final Module configurationModule = testNGConfiguration.getConfigurationModule().getModule();
@@ -33,6 +33,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.theoryinpractice.testng.model.TestData;
import com.theoryinpractice.testng.model.TestNGTestObject;
import icons.TestngIcons;
import org.jetbrains.annotations.NotNull;
@@ -72,7 +73,8 @@ public class TestNGConfigurationType implements ConfigurationType
return false;
else {
final PsiElement element = location.getPsiElement();
if (testobject.isConfiguredByElement(element)) {
final TestNGTestObject testNGTestObject = TestNGTestObject.fromConfig(config);
if (testNGTestObject != null && testNGTestObject.isConfiguredByElement(element)) {
final Module configurationModule = config.getConfigurationModule().getModule();
if (Comparing.equal(location.getModule(), configurationModule)) return true;
@@ -18,16 +18,15 @@ package com.theoryinpractice.testng.model;
import com.intellij.execution.ExternalizablePath;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.Location;
import com.intellij.execution.configurations.JavaRunConfigurationModule;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPackage;
import java.util.*;
@@ -174,26 +173,6 @@ public class TestData implements Cloneable
return data;
}
public String getGeneratedName(JavaRunConfigurationModule runconfigurationmodule) {
if (TestType.PACKAGE.getType().equals(TEST_OBJECT)) if (getPackageName().length() == 0) return "<default>";
else return getPackageName();
String name = JavaExecutionUtil.getPresentableClassName(getMainClassName());
if (TestType.METHOD.getType().equals(TEST_OBJECT)) {
return name + '.' + getMethodName();
}
else if (TestType.SUITE.getType().equals(TEST_OBJECT)) {
return getSuiteName();
}
else {
if (TestType.PATTERN.getType().equals(TEST_OBJECT)) {
final int size = myPatterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(myPatterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
return name;
}
}
public String getMainClassName() {
return MAIN_CLASS_NAME == null ? "" : MAIN_CLASS_NAME;
}
@@ -217,28 +196,6 @@ public class TestData implements Cloneable
return JavaExecutionUtil.findModule(psiclass);
}
public boolean isConfiguredByElement(PsiElement element) {
if (TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
if (element instanceof PsiPackage) {
return Comparing.strEqual(PACKAGE_NAME, ((PsiPackage) element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(PACKAGE_NAME, psiPackage.getQualifiedName());
}
}
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod && TEST_OBJECT.equals(TestType.METHOD.getType())) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
return aClass != null &&
Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(METHOD_NAME, ((PsiMethod) element).getName());
} else if (element instanceof PsiClass && TEST_OBJECT.equals(TestType.CLASS.getType())) {
return Comparing.strEqual(MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
public Map<String, String> getEnvs() {
return ENVS;
}
@@ -0,0 +1,95 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestClass extends TestNGTestObject {
public TestNGTestClass(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//it's a class
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
})) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
calculateDependencies(null, classes, psiClass);
}
@Override
public String getGeneratedName() {
return JavaExecutionUtil.getPresentableClassName(myConfig.getPersistantData().getMainClassName());
}
@Override
public String getActionName() {
return JavaExecutionUtil.getShortClassName(myConfig.getPersistantData().MAIN_CLASS_NAME);
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiClass) {
return Comparing.strEqual(myConfig.getPersistantData().getMethodName(), JavaExecutionUtil.getRuntimeQualifiedName((PsiClass) element));
}
return false;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class TestNGTestGroup extends TestNGTestObject {
public TestNGTestGroup(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
//for a group, we include all classes
final TestClassFilter classFilter =
new TestClassFilter(data.getScope().getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
PsiClass[] testClasses = TestNGUtil.getAllTestClasses(classFilter, false);
if (testClasses != null) {
for (PsiClass c : testClasses) {
classes.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
}
}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getGroupName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
//check group exist?
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestMethod extends TestNGTestObject {
public TestNGTestMethod(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(
new Computable<PsiClass>() {
@Nullable
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), data.getMainClassName().replace('/', '.'), null, true, getSearchScope());
}
}
);
if (psiClass == null) {
throw new CantRunException("No tests found in the class \"" + data.getMainClassName() + '\"');
}
if (null == ApplicationManager.getApplication().runReadAction(
new Computable<String>() {
@Nullable
public String compute() {
return psiClass.getQualifiedName();
}
}
)) {
throw new CantRunException("Cannot test anonymous or local class \"" + data.getMainClassName() + '\"');
}
collectTestMethods(classes, psiClass, data.getMethodName());
}
@Override
public String getGeneratedName() {
final TestData data = myConfig.getPersistantData();
return JavaExecutionUtil.getPresentableClassName(data.getMainClassName()) + '.' + data.getMethodName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getMethodName() + "()";
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
final SourceScope scope = data.getScope().getSourceScope(myConfig);
if (scope == null) {
throw new RuntimeConfigurationException("Invalid scope specified");
}
PsiClass psiClass = JavaPsiFacade.getInstance(myConfig.getProject()).findClass(data.getMainClassName(), scope.getGlobalSearchScope());
if (psiClass == null) throw new RuntimeConfigurationException("Class '" + data.getMainClassName() + "' not found");
PsiMethod[] methods = psiClass.findMethodsByName(data.getMethodName(), true);
if (methods.length == 0) {
throw new RuntimeConfigurationException("Method '" + data.getMethodName() + "' not found");
}
for (PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) {
throw new RuntimeConfigurationException("Non public method '" + data.getMethodName() + "'specified");
}
}
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
element = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class, false);
if (element instanceof PsiMethod) {
final PsiClass aClass = ((PsiMethod) element).getContainingClass();
final TestData data = myConfig.getPersistantData();
return aClass != null &&
Comparing.strEqual(data.MAIN_CLASS_NAME, JavaExecutionUtil.getRuntimeQualifiedName(aClass)) &&
Comparing.strEqual(data.METHOD_NAME, ((PsiMethod) element).getName());
}
return false;
}
}
@@ -0,0 +1,247 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.AnnotatedMembersSearch;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public abstract class TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestObject.class.getName());
protected final TestNGConfiguration myConfig;
public TestNGTestObject(TestNGConfiguration config) {
myConfig = config;
}
public static TestNGTestObject fromConfig(TestNGConfiguration config) {
final TestData data = config.getPersistantData();
if (data.TEST_OBJECT.equals(TestType.PACKAGE.getType())) {
return new TestNGTestPackage(config);
}
if (data.TEST_OBJECT.equals(TestType.CLASS.getType())) {
return new TestNGTestClass(config);
}
if (data.TEST_OBJECT.equals(TestType.METHOD.getType())) {
return new TestNGTestMethod(config);
}
if (data.TEST_OBJECT.equals(TestType.GROUP.getType())) {
return new TestNGTestGroup(config);
}
if (data.TEST_OBJECT.equals(TestType.PATTERN.getType())) {
return new TestNGTestPattern(config);
}
if (data.TEST_OBJECT.equals(TestType.SUITE.getType())){
return new TestNGTestSuite(config);
}
assert false : data.TEST_OBJECT;
return null;
}
public abstract void fillTestObjects(final Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException;
public abstract String getGeneratedName();
public abstract String getActionName();
public abstract void checkConfiguration() throws RuntimeConfigurationException;
public boolean isConfiguredByElement(PsiElement element) {
return false;
}
protected void calculateDependencies(PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
@Nullable final PsiClass... classes) {
calculateDependencies(methods, results, new LinkedHashSet<PsiMember>(), classes);
}
private void calculateDependencies(final PsiMethod[] methods,
final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
@Nullable final PsiClass... classes) {
if (classes != null && classes.length > 0) {
final Set<String> groupDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(groupDependencies, "dependsOnGroups", methods, classes);
final Set<PsiMember> membersToCheckNow = new LinkedHashSet<PsiMember>();
if (!groupDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = classes[0].getProject();
final PsiClass testAnnotation =
JavaPsiFacade.getInstance(project).findClass(TestNGUtil.TEST_ANNOTATION_FQN, GlobalSearchScope.allScope(project));
LOG.assertTrue(testAnnotation != null);
for (PsiMember psiMember : AnnotatedMembersSearch.search(testAnnotation, getSearchScope())) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(psiMember, TestNGUtil.TEST_ANNOTATION_FQN);
if (TestNGUtil.isAnnotatedWithParameter(annotation, "groups", groupDependencies)) {
if (appendMember(psiMember, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(psiMember);
}
}
}
}
});
}
collectDependsOnMethods(results, alreadyMarkedToBeChecked, membersToCheckNow, methods, classes);
if (methods == null) {
for (PsiClass c : classes) {
results.put(c, new LinkedHashMap<PsiMethod, List<String>>());
}
} else {
for (PsiMember psiMember : membersToCheckNow) {
PsiClass psiClass;
PsiMethod[] meths = null;
if (psiMember instanceof PsiMethod) {
psiClass = psiMember.getContainingClass();
meths = new PsiMethod[] {(PsiMethod)psiMember};
} else {
psiClass = (PsiClass)psiMember;
}
calculateDependencies(meths, results, alreadyMarkedToBeChecked, psiClass);
}
}
}
}
private static void collectDependsOnMethods(final Map<PsiClass, Map<PsiMethod, List<String>>> results,
final Set<PsiMember> alreadyMarkedToBeChecked,
final Set<PsiMember> membersToCheckNow,
final PsiMethod[] methods,
final PsiClass... classes) {
final PsiClass[] psiClasses;
if (methods != null && methods.length > 0) {
final Set<PsiClass> containingClasses = new LinkedHashSet<PsiClass>();
for (final PsiMethod method : methods) {
containingClasses.add(ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return method.getContainingClass();
}
}));
}
psiClasses = containingClasses.toArray(new PsiClass[containingClasses.size()]);
} else {
psiClasses = classes;
}
for (final PsiClass containingClass : psiClasses) {
final Set<String> testMethodDependencies = new LinkedHashSet<String>();
TestNGUtil.collectAnnotationValues(testMethodDependencies, "dependsOnMethods", methods, containingClass);
if (!testMethodDependencies.isEmpty()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
final Project project = containingClass.getProject();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String dependency : testMethodDependencies) {
final String className = StringUtil.getPackageName(dependency);
final String methodName = StringUtil.getShortName(dependency);
if (StringUtil.isEmpty(className)) {
checkClassMethods(methodName, containingClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
else {
final PsiClass aClass = psiFacade.findClass(className, containingClass.getResolveScope());
if (aClass != null) {
checkClassMethods(methodName, aClass, alreadyMarkedToBeChecked, membersToCheckNow, results);
}
}
}
}
});
}
}
}
private static void checkClassMethods(String methodName,
PsiClass containingClass,
Set<PsiMember> alreadyMarkedToBeChecked,
Set<PsiMember> membersToCheckNow,
Map<PsiClass, Map<PsiMethod, List<String>>> results) {
final PsiMethod[] psiMethods = containingClass.findMethodsByName(methodName, true);
for (PsiMethod method : psiMethods) {
if (AnnotationUtil.isAnnotated(method, TestNGUtil.TEST_ANNOTATION_FQN, false) &&
appendMember(method, alreadyMarkedToBeChecked, results)) {
membersToCheckNow.add(method);
}
}
}
private static boolean appendMember(final PsiMember psiMember,
final Set<PsiMember> underConsideration,
final Map<PsiClass, Map<PsiMethod, List<String>>> results) {
boolean result = false;
final PsiClass psiClass = psiMember instanceof PsiClass ? ((PsiClass)psiMember) : psiMember.getContainingClass();
Map<PsiMethod, List<String>> psiMethods = results.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
results.put(psiClass, psiMethods);
if (psiMember instanceof PsiClass) {
result = underConsideration.add(psiMember);
}
}
if (psiMember instanceof PsiMethod) {
final boolean add = psiMethods.put((PsiMethod)psiMember, Collections.<String>emptyList()) != null;
if (add) {
return underConsideration.add(psiMember);
}
return false;
}
return result;
}
@NotNull
protected GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
return data.TEST_OBJECT.equals(TestType.PACKAGE.getType())
? myConfig.getPersistantData().getScope().getSourceScope(myConfig).getGlobalSearchScope()
: module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(myConfig.getProject());
}
protected void collectTestMethods(Map<PsiClass, Map<PsiMethod, List<String>>> classes, final PsiClass psiClass, final String methodName) {
final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
new Computable<PsiMethod[]>() {
public PsiMethod[] compute() {
return psiClass.findMethodsByName(methodName, true);
}
}
);
calculateDependencies(methods, classes, psiClass);
Map<PsiMethod, List<String>> psiMethods = classes.get(psiClass);
if (psiMethods == null) {
psiMethods = new LinkedHashMap<PsiMethod, List<String>>();
classes.put(psiClass, psiMethods);
}
for (PsiMethod method : methods) {
psiMethods.put(method, Collections.<String>emptyList());
}
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.JavaExecutionUtil;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public class TestNGTestPackage extends TestNGTestObject {
public TestNGTestPackage(TestNGConfiguration configuration) {
super(configuration);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {
final String packageName = myConfig.getPersistantData().getPackageName();
PsiPackage psiPackage = ApplicationManager.getApplication().runReadAction(
new Computable<PsiPackage>() {
@Nullable
public PsiPackage compute() {
return JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(packageName);
}
}
);
if (psiPackage == null) {
throw CantRunException.packageNotFound(packageName);
}
else {
TestSearchScope scope = myConfig.getPersistantData().getScope();
//TODO we should narrow this down by module really, if that's what's specified
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true);
TestClassFilter filter = projectFilter.intersectionWith(PackageScope.packageScope(psiPackage, true));
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(filter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in the package \"" + packageName + '\"');
}
}
}
@Override
public String getGeneratedName() {
final String packageName = myConfig.getPersistantData().getPackageName();
return packageName.length() == 0 ? "<default>" : packageName;
}
@Override
public String getActionName() {
String s = myConfig.getName();
if (!myConfig.isGeneratedName()) return '\"' + s + '\"';
if (myConfig.getPersistantData().getPackageName().trim().length() > 0) {
return "Tests in \"" + myConfig.getPersistantData().getPackageName() + '\"';
}
else {
return "All Tests";
}
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
PsiPackage psiPackage = JavaPsiFacade.getInstance(myConfig.getProject()).findPackage(data.getPackageName());
if (psiPackage == null) throw new RuntimeConfigurationException("Package '" + data.getPackageName() + "' not found");
}
@Override
public boolean isConfiguredByElement(PsiElement element) {
final String packageName = myConfig.getPersistantData().getPackageName();
if (element instanceof PsiPackage) {
return Comparing.strEqual(packageName, ((PsiPackage)element).getQualifiedName());
} else if (element instanceof PsiDirectory) {
final PsiPackage psiPackage = JavaDirectoryService.getInstance().getPackage(((PsiDirectory)element));
return psiPackage != null && Comparing.strEqual(packageName, psiPackage.getQualifiedName());
}
return false;
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.ClassUtil;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.util.TestNGUtil;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class TestNGTestPattern extends TestNGTestObject {
private static final Logger LOG = Logger.getInstance("#" + TestNGTestPattern.class.getName());
public TestNGTestPattern(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes)
throws CantRunException {
final TestData data = myConfig.getPersistantData();
for (final String pattern : data.getPatterns()) {
final String className;
final String methodName;
if (pattern.contains(",")) {
methodName = StringUtil.getShortName(pattern, ',');
className = StringUtil.getPackageName(pattern, ',');
} else {
className = pattern;
methodName = null;
}
final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Nullable
@Override
public PsiClass compute() {
return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), className.replace('/', '.'), null, true, getSearchScope());
}
});
if (psiClass != null) {
final Boolean hasTest = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return TestNGUtil.hasTest(psiClass);
}
});
if (hasTest) {
if (StringUtil.isEmpty(methodName)) {
calculateDependencies(null, classes, psiClass);
}
else {
collectTestMethods(classes, psiClass, methodName);
}
} else {
throw new CantRunException("No tests found in class " + className);
}
}
}
if (classes.size() != data.getPatterns().size()) {
TestSearchScope scope = myConfig.getPersistantData().getScope();
final List<Pattern> compilePatterns = new ArrayList<Pattern>();
for (String p : data.getPatterns()) {
final Pattern compilePattern;
try {
compilePattern = Pattern.compile(p);
}
catch (PatternSyntaxException e) {
continue;
}
if (compilePattern != null) {
compilePatterns.add(compilePattern);
}
}
TestClassFilter projectFilter =
new TestClassFilter(scope.getSourceScope(myConfig).getGlobalSearchScope(), myConfig.getProject(), true, true){
@Override
public boolean isAccepted(PsiClass psiClass) {
if (super.isAccepted(psiClass)) {
final String qualifiedName = psiClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
for (Pattern pattern : compilePatterns) {
if (pattern.matcher(qualifiedName).matches()) return true;
}
}
return false;
}
};
calculateDependencies(null, classes, TestNGUtil.getAllTestClasses(projectFilter, false));
if (classes.size() == 0) {
throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"');
}
}
}
@Override
public String getGeneratedName() {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
final int size = patterns.size();
if (size == 0) return "Temp suite";
return StringUtil.getShortName(patterns.iterator().next()) + (size > 1 ? " and " + (size - 1) + " more" : "");
}
@Override
public String getActionName() {
return getGeneratedName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final Set<String> patterns = myConfig.getPersistantData().getPatterns();
if (patterns.isEmpty()) {
throw new RuntimeConfigurationWarning("No pattern selected");
}
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.theoryinpractice.testng.model;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import org.testng.xml.Parser;
import java.util.List;
import java.util.Map;
public class TestNGTestSuite extends TestNGTestObject {
private static final Object PARSE_LOCK = new Object();
public TestNGTestSuite(TestNGConfiguration config) {
super(config);
}
@Override
public void fillTestObjects(Map<PsiClass, Map<PsiMethod, List<String>>> classes) throws CantRunException {}
@Override
public String getGeneratedName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public String getActionName() {
return myConfig.getPersistantData().getSuiteName();
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
final TestData data = myConfig.getPersistantData();
try {
final Parser parser = new Parser(data.getSuiteName());
parser.setLoadClasses(false);
synchronized (PARSE_LOCK) {
parser.parse();//try to parse suite.xml
}
}
catch (Exception e) {
throw new RuntimeConfigurationException("Unable to parse '" + data.getSuiteName() + "' specified");
}
}
}
@@ -436,7 +436,7 @@ public class TestNGUtil {
public void run() {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final Collection<PsiClass> set = new HashSet<PsiClass>();
final Collection<PsiClass> set = new LinkedHashSet<PsiClass>();
PsiManager manager = PsiManager.getInstance(filter.getProject());
GlobalSearchScope scope = filter.getScope();
GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());