package org.jetbrains.plugins.cucumber.java; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.cucumber.java.config.CucumberConfigUtil; import org.jetbrains.plugins.cucumber.java.steps.reference.CucumberJavaAnnotationProvider; import org.jetbrains.plugins.cucumber.psi.*; import java.util.List; import java.util.Set; import static com.intellij.psi.util.PsiTreeUtil.getChildOfType; import static com.intellij.psi.util.PsiTreeUtil.getChildrenOfTypeAsList; public class CucumberJavaUtil { public static final String CUCUMBER_STEP_ANNOTATION_PREFIX_1_0 = "cucumber.annotation."; public static final String CUCUMBER_STEP_ANNOTATION_PREFIX_1_1 = "cucumber.api.java."; private static String getCucumberAnnotationSuffix(@NotNull String name) { if (name.startsWith(CUCUMBER_STEP_ANNOTATION_PREFIX_1_0)) { return name.substring(CUCUMBER_STEP_ANNOTATION_PREFIX_1_0.length()); } else if (name.startsWith(CUCUMBER_STEP_ANNOTATION_PREFIX_1_1)) { return name.substring(CUCUMBER_STEP_ANNOTATION_PREFIX_1_1.length()); } else { name = ""; } return name; } public static String getCucumberPendingExceptionFqn(@NotNull final PsiElement context) { final String version = CucumberConfigUtil.getCucumberCoreVersion(context); if (version == null || version.compareTo(CucumberConfigUtil.CUCUMBER_VERSION_1_1) >= 0) { return "cucumber.api.PendingException"; } return "cucumber.runtime.PendingException"; } @Nullable private static String getAnnotationName(@NotNull final PsiAnnotation annotation) { final Ref<String> qualifiedAnnotationName = new Ref<>(); ApplicationManager.getApplication().runReadAction(() -> { String qualifiedName = annotation.getQualifiedName(); qualifiedAnnotationName.set(qualifiedName); } ); return qualifiedAnnotationName.get(); } public static boolean isCucumberStepAnnotation(@NotNull final PsiAnnotation annotation) { final String annotationName = getAnnotationName(annotation); if (annotationName == null) return false; final String annotationSuffix = getCucumberAnnotationSuffix(annotationName); if (annotationSuffix.contains(".")) { return true; } for (String providedAnnotations : CucumberJavaAnnotationProvider.getCucumberStepAnnotations()) { if (providedAnnotations.equals(annotationName)) { return true; } } return false; } public static boolean isCucumberHookAnnotation(@NotNull final PsiAnnotation annotation) { final String annotationName = getAnnotationName(annotation); if (annotationName == null) return false; final String annotationSuffix = getCucumberAnnotationSuffix(annotationName); for (String providedAnnotations : CucumberJavaAnnotationProvider.getCucumberHookAnnotations()) { if (providedAnnotations.equals(annotationSuffix)) { return true; } } return false; } @Nullable public static PsiAnnotationMemberValue getAnnotationValue(@NotNull final PsiAnnotation stepAnnotation) { final PsiNameValuePair[] attributes = stepAnnotation.getParameterList().getAttributes(); PsiNameValuePair valuePair = null; if (attributes.length > 0) { for (int i = 1; i < attributes.length; i++) { PsiNameValuePair pair = attributes[i]; final String pairName = pair.getName(); if (pairName != null && pairName.equals("value")) { valuePair = pair; break; } } if (valuePair == null) { valuePair = attributes[0]; } } return valuePair != null ? valuePair.getValue() : null; } public static boolean isStepDefinition(@NotNull final PsiMethod method) { final PsiAnnotation stepAnnotation = getCucumberStepAnnotation(method); return stepAnnotation != null && getAnnotationValue(stepAnnotation) != null; } public static boolean isHook(@NotNull final PsiMethod method) { return getCucumberHookAnnotation(method) != null; } public static boolean isStepDefinitionClass(@NotNull final PsiClass clazz) { PsiMethod[] methods = clazz.getAllMethods(); for (PsiMethod method : methods) { if (getCucumberStepAnnotation(method) != null || getCucumberHookAnnotation(method) != null) return true; } return false; } @Nullable public static PsiAnnotation getCucumberStepAnnotation(PsiMethod method) { if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { return null; } final PsiAnnotation[] annotations = method.getModifierList().getAnnotations(); for (PsiAnnotation annotation : annotations) { if (annotation != null && isCucumberStepAnnotation(annotation)) { return annotation; } } return null; } @Nullable public static PsiAnnotation getCucumberHookAnnotation(PsiMethod method) { if (!method.hasModifierProperty(PsiModifier.PUBLIC)) { return null; } final PsiAnnotation[] annotations = method.getModifierList().getAnnotations(); for (PsiAnnotation annotation : annotations) { if (annotation != null && isCucumberHookAnnotation(annotation)) { return annotation; } } return null; } @Nullable public static String getPatternFromStepDefinition(@NotNull final PsiAnnotation stepAnnotation) { String result = null; if (stepAnnotation.getParameterList().getAttributes().length > 0) { final PsiElement annotationValue = stepAnnotation.getParameterList().getAttributes()[0].getValue(); if (annotationValue != null) { final PsiElement patternLiteral = annotationValue.getFirstChild(); if (patternLiteral != null) { final String patternContainer = patternLiteral.getText(); result = patternContainer.substring(1, patternContainer.length() - 1).replace("\\\\", "\\"); } } } return result; } @Nullable private static String getPackageOfStepDef(GherkinStep[] steps) { for (GherkinStep step : steps) { final String pack = getPackageOfStep(step); if (pack != null) return pack; } return null; } @NotNull public static String getPackageOfStepDef(final PsiElement element) { PsiFile file = element.getContainingFile(); if (file instanceof GherkinFile) { GherkinFeature feature = getChildOfType(file, GherkinFeature.class); if (feature != null) { List<GherkinScenario> scenarioList = getChildrenOfTypeAsList(feature, GherkinScenario.class); for (GherkinScenario scenario : scenarioList) { String result = getPackageOfStepDef(scenario.getSteps()); if (result != null) { return result; } } List<GherkinScenarioOutline> scenarioOutlineList = getChildrenOfTypeAsList(feature, GherkinScenarioOutline.class); for (GherkinScenarioOutline scenario : scenarioOutlineList) { String result = getPackageOfStepDef(scenario.getSteps()); if (result != null) { return result; } } } } return ""; } public static String getPackageOfStep(GherkinStep step) { for (PsiReference ref : step.getReferences()) { PsiElement refElement = ref.resolve(); if (refElement != null && refElement instanceof PsiMethod) { PsiClassOwner file = (PsiClassOwner)refElement.getContainingFile(); final String packageName = file.getPackageName(); if (StringUtil.isNotEmpty(packageName)) { return packageName; } } } return null; } public static void addGlue(String glue, Set<String> glues) { boolean covered = false; final Set<String> toRemove = ContainerUtil.newHashSet(); for (String existedGlue : glues) { if (glue.startsWith(existedGlue + ".")) { covered = true; break; } else if (existedGlue.startsWith(glue + ".")) { toRemove.add(existedGlue); } } for (String removing : toRemove) { glues.remove(removing); } if (!covered) { glues.add(glue); } } }