package org.elixir_lang.mix; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubIndex; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Function; import org.elixir_lang.psi.NamedElement; import org.elixir_lang.psi.call.Call; import org.elixir_lang.psi.call.StubBased; import org.elixir_lang.psi.stub.index.AllName; import org.elixir_lang.structure_view.element.Quote; import org.elixir_lang.structure_view.element.modular.Implementation; import org.elixir_lang.structure_view.element.modular.Module; import org.elixir_lang.structure_view.element.modular.Protocol; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.Set; public class TestFinder implements com.intellij.testIntegration.TestFinder { private static final String TEST_SUFFIX = "Test"; @NotNull private static Collection<PsiElement> corresponding(@NotNull PsiElement element, @NotNull Function<String, String> correspondingName, @NotNull Condition<Call> correspondingCallCondition) { Call sourceElement = sourceElement(element); Collection<PsiElement> correspondingCollection = new ArrayList<PsiElement>(); if (sourceElement != null && sourceElement instanceof StubBased) { StubBased sourceStubBased = (StubBased) sourceElement; @SuppressWarnings("unchecked") Set<String> canonicalNameSet = sourceStubBased.canonicalNameSet(); if (!canonicalNameSet.isEmpty()) { Project project = element.getProject(); GlobalSearchScope scope = GlobalSearchScope.projectScope(project); for (String canonicalName : canonicalNameSet) { String correspondingCanonicalName = correspondingName.fun(canonicalName); if (correspondingCanonicalName != null) { Collection<NamedElement> correspondingElements = StubIndex.getElements( AllName.KEY, correspondingCanonicalName, project, scope, NamedElement.class ); for (NamedElement correspondingElement : correspondingElements) { if (correspondingElement instanceof Call) { Call correspondingCall = (Call) correspondingElement; if (correspondingCallCondition.value(correspondingCall)) { correspondingCollection.add(correspondingCall); } } } } } } } return correspondingCollection; } private static boolean isModular(@NotNull Call call) { return Implementation.is(call) || Module.is(call) || Protocol.is(call) || Quote.is(call); } @Nullable private static Call parentCallSourceElement(@NotNull PsiElement from) { Call parentCall = PsiTreeUtil.getParentOfType(from, Call.class); Call sourceElement = null; if (parentCall != null) { sourceElement = sourceElement(parentCall); } return sourceElement; } @Nullable private static Call sourceElement(@NotNull Call from) { Call sourceElement; if (isModular(from)) { sourceElement = from; } else { sourceElement = parentCallSourceElement(from); } return sourceElement; } @Nullable private static Call sourceElement(@NotNull PsiElement from) { Call sourceElement; if (from instanceof Call) { sourceElement = sourceElement((Call) from); } else { sourceElement = parentCallSourceElement(from); } return sourceElement; } @Nullable @Override public Call findSourceElement(@NotNull PsiElement from) { return sourceElement(from); } @NotNull @Override public Collection<PsiElement> findTestsForClass(@NotNull PsiElement element) { return corresponding( element, new Function<String, String>() { @Override public String fun(@NotNull String canonicalName) { return canonicalName + TEST_SUFFIX; } }, new Condition<Call>() { @Override public boolean value(Call call) { return Module.is(call); } } ); } @NotNull @Override public Collection<PsiElement> findClassesForTest(@NotNull PsiElement element) { return corresponding( element, new Function<String, String>() { @Override public String fun(String canonicalName) { String correspondingCanonicalName = null; if (canonicalName.endsWith(TEST_SUFFIX)) { correspondingCanonicalName = canonicalName.substring(0, canonicalName.length() - TEST_SUFFIX.length()); } return correspondingCanonicalName; } }, new Condition<Call>() { @Override public boolean value(Call call) { return isModular(call); } } ); } @Override public boolean isTest(@NotNull PsiElement element) { Call sourceElement = findSourceElement(element); boolean isTest = false; if (sourceElement != null && sourceElement instanceof StubBased) { StubBased sourceStubBased = (StubBased) sourceElement; @SuppressWarnings("unchecked") Set<String> canonicalNameSet = sourceStubBased.canonicalNameSet(); if (!canonicalNameSet.isEmpty()) { for (String canonicalName : canonicalNameSet) { if (canonicalName.endsWith("Test")) { isTest = true; break; } } } } return isTest; } }