package com.intellij.lang.javascript.flex.flexunit; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.lang.javascript.JavaScriptSupportLoader; import com.intellij.lang.javascript.psi.JSFunction; import com.intellij.lang.javascript.psi.ecmal4.JSClass; import com.intellij.lang.javascript.psi.impl.JSChangeUtil; import com.intellij.lang.javascript.psi.resolve.JSInheritanceUtil; import com.intellij.lang.javascript.refactoring.util.JSMemberInfo; import com.intellij.lang.javascript.validation.fixes.CreateClassOrInterfaceFix; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testIntegration.TestCreator; import com.intellij.util.Consumer; import gnu.trove.THashSet; import java.util.Collections; import java.util.Set; import static com.intellij.lang.javascript.psi.JSFunction.FunctionKind; public class FlexUnitTestCreator implements TestCreator { public boolean isAvailable(final Project project, final Editor editor, final PsiFile file) { final VirtualFile vFile = file.getVirtualFile(); return FlexUnitTestFinder.findContextClass(file) != null && vFile != null && !ProjectRootManager.getInstance(project).getFileIndex().isInTestSourceContent(vFile); } public void createTest(final Project project, final Editor editor, final PsiFile file) { final JSClass jsClass = FlexUnitTestFinder.findContextClass(file); if (jsClass == null) return; final String testClassName; final String packageName; final JSClass superClass; final PsiDirectory targetDirectory; final boolean generateSetUp; final boolean generateTearDown; final JSMemberInfo[] selectedMemberInfos; if (ApplicationManager.getApplication().isUnitTestMode()) { testClassName = jsClass.getName() + "Test"; packageName = StringUtil.getPackageName(jsClass.getQualifiedName()); superClass = null; targetDirectory = jsClass.getContainingFile().getContainingDirectory(); generateSetUp = true; generateTearDown = true; selectedMemberInfos = new JSMemberInfo[0]; } else { final CreateFlexUnitTestDialog dialog = new CreateFlexUnitTestDialog(ModuleUtilCore.findModuleForPsiElement(jsClass), jsClass); dialog.show(); if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return; } testClassName = dialog.getTestClassName(); packageName = dialog.getPackageName(); superClass = dialog.getSuperClass(); targetDirectory = dialog.getTargetDirectory(); generateSetUp = dialog.isGenerateSetUp(); generateTearDown = dialog.isGenerateTearDown(); selectedMemberInfos = dialog.getSelectedMemberInfos(); } final Consumer<JSClass> postProcessRunnable = createdClass -> { final String methodsText = getMethodsText(createdClass, generateSetUp, generateTearDown, selectedMemberInfos); if (!methodsText.isEmpty()) { final PsiElement methods = JSChangeUtil.createJSTreeFromText(project, "{" + methodsText + "}", JavaScriptSupportLoader.ECMA_SCRIPT_L4).getPsi(); if (methods != null) { for (final PsiElement psiElement : PsiTreeUtil.getChildrenOfTypeAsList(methods, JSFunction.class)) { createdClass.add(psiElement); } } } CodeStyleManager.getInstance(project).reformat(createdClass); createdClass.navigate(true); }; CommandProcessor.getInstance().executeCommand(project, () -> CreateClassOrInterfaceFix.createClass(CreateClassOrInterfaceFix.ACTION_SCRIPT_CLASS_WITH_SUPERS_TEMPLATE_NAME, testClassName, packageName, superClass, Collections.emptyList(), targetDirectory, CodeInsightBundle.message("intention.create.test"), true, Collections.emptyMap(), postProcessRunnable), CodeInsightBundle.message("intention.create.test"), null); } private static String getMethodsText(final JSClass createdClass, final boolean generateSetUp, final boolean generateTearDown, final JSMemberInfo[] selectedMemberInfos) { final StringBuilder builder = new StringBuilder(); builder.append(generateSetUp ? JSInheritanceUtil .findMember("setUp", createdClass, JSInheritanceUtil.SearchedMemberType.Methods, FunctionKind.SIMPLE, true) == null ? "[Before]\npublic function setUp():void{\n\n}" : "[Before]\npublic override function setUp():void{\nsuper.setUp();\n}" : ""); builder.append(generateTearDown ? JSInheritanceUtil.findMember("tearDown", createdClass, JSInheritanceUtil.SearchedMemberType.Methods, FunctionKind.SIMPLE, true) == null ? "[After]\npublic function tearDown():void{\n\n}" : "[After]\npublic override function tearDown():void{\nsuper.tearDown();\n}" : ""); final Set<String> processedNames = new THashSet<>(); // because getters and setters have same name for (final JSMemberInfo info : selectedMemberInfos) { final String name = info.getMember().getName(); if (!processedNames.contains(name)) { processedNames.add(name); final String testName = "test" + capitalizeFirstCharacter(name); builder.append("[Test]\npublic function ").append(testName).append("():void{\n\n}"); } } return builder.toString(); } private static String capitalizeFirstCharacter(final String s) { if (StringUtil.isEmpty(s)) return s; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } }