blob: e19f9bfb50741b964f3c46fb2fb4dc33f2d90d84 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.java.run.producers;
import com.intellij.execution.Location;
import com.intellij.execution.PsiLocation;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** Helper functions for getting selected test methods. */
public class TestMethodSelectionUtil {
/**
* Get all test methods directly or indirectly selected in the given context. This includes
* methods selected in the Structure panel, as well as methods the context location is inside of.
*
* @param context The context to get selected test methods from.
* @param allMustMatch If true, will return null if any selected elements are not test methods.
* @return A list of test methods (with at least one element), or null if:
* <ul>
* <li>There are no selected test methods
* <li>{@code allMustMatch} is true, but elements other than test methods are selected
* </ul>
*
* @see #getDirectlySelectedMethods(ConfigurationContext, boolean)
* @see #getIndirectlySelectedMethod(ConfigurationContext)
*/
@Nullable
public static List<PsiMethod> getSelectedMethods(
@NotNull ConfigurationContext context, boolean allMustMatch) {
List<PsiMethod> directlySelectedMethods = getDirectlySelectedMethods(context, allMustMatch);
if (directlySelectedMethods != null && directlySelectedMethods.size() > 0) {
return directlySelectedMethods;
}
if (allMustMatch && JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
return null;
}
PsiMethod indirectlySelectedMethod = getIndirectlySelectedMethod(context);
if (indirectlySelectedMethod != null) {
return Collections.singletonList(indirectlySelectedMethod);
}
return null;
}
/**
* Get all test methods directly or indirectly selected in the given context. This includes
* methods selected in the Structure panel, as well as methods the context location is inside of.
*
* @param context The context to get selected test methods from.
* @return A list of test methods (with at least one element), or null if:
* <ul>
* <li>There are no selected test methods
* <li>Any elements other than test methods are selected
* </ul>
*
* @see #getDirectlySelectedMethods(ConfigurationContext, boolean)
* @see #getIndirectlySelectedMethod(ConfigurationContext)
*/
@Nullable
public static List<PsiMethod> getSelectedMethods(@NotNull ConfigurationContext context) {
return getSelectedMethods(context, true);
}
/**
* Get all test methods directly selected in the given context. This includes, for example,
* methods selected from the Structure panel. It does not include methods the context location is
* inside of. Note that methods may belong to different classes (possible if methods are selected
* from the Project panel with "Show Members" checked), and methods in abstract classes are not
* returned.
*
* @param context The context to get selected test methods from.
* @param allMustMatch If true, will return null if any selected elements are not test methods.
* @return A list of test methods (possibly empty), or null if:
* <ul>
* <li>There is no selection
* <li>{@code allMustMatch} is true, but elements other than test methods are selected
* </ul>
*/
@Nullable
public static List<PsiMethod> getDirectlySelectedMethods(
@NotNull ConfigurationContext context, boolean allMustMatch) {
final DataContext dataContext = context.getDataContext();
PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
if (elements == null) {
return null;
}
List<PsiMethod> methods = new ArrayList<>();
for (PsiElement element : elements) {
if (element instanceof PsiMethod) {
PsiMethod method = (PsiMethod) element;
if (JUnitUtil.isTestMethod(PsiLocation.fromPsiElement(method))) {
methods.add(method);
} else if (allMustMatch) {
return null;
}
} else if (allMustMatch) {
return null;
}
}
return methods;
}
/**
* Get a test method which is considered selected in the given context, belonging to a
* non-abstract class. The context location may be the method itself, or anywhere inside the
* method.
*
* @param context The context to search for a test method in.
* @return A test method, or null if none are found.
*/
@Nullable
public static PsiMethod getIndirectlySelectedMethod(@NotNull ConfigurationContext context) {
final Location<?> contextLocation = context.getLocation();
if (contextLocation == null) {
return null;
}
Iterator<Location<PsiMethod>> locationIterator =
contextLocation.getAncestors(PsiMethod.class, false);
while (locationIterator.hasNext()) {
Location<PsiMethod> methodLocation = locationIterator.next();
if (JUnitUtil.isTestMethod(methodLocation)) {
return methodLocation.getPsiElement();
}
}
return null;
}
}