/** * Copyright (C) 2005 - 2013 Eric Van Dewoestine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.eclim.plugin.jdt.command.junit; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclim.Services; import org.eclim.annotation.Command; import org.eclim.command.CommandLine; import org.eclim.command.Options; import org.eclim.plugin.jdt.command.impl.ImplCommand; import org.eclim.plugin.jdt.util.JavaUtils; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.junit.JUnitCorePlugin; import org.eclipse.jdt.internal.junit.Messages; import org.eclipse.jdt.internal.junit.util.JUnitStubUtility; import org.eclipse.jdt.internal.junit.wizards.WizardMessages; import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; import org.eclipse.text.edits.MultiTextEdit; /** * Command to handle creation of junit test stubs. * * @author Eric Van Dewoestine */ @Command( name = "java_junit_impl", options = "REQUIRED p project ARG," + "REQUIRED f file ARG," + "OPTIONAL o offset ARG," + "OPTIONAL e encoding ARG," + "OPTIONAL t type ARG," + "OPTIONAL s superType ARG," + "OPTIONAL m methods ARG" ) public class JUnitImplCommand extends ImplCommand { private ThreadLocal<ITypeBinding> base = new ThreadLocal<ITypeBinding>(); @Override public Object execute(CommandLine commandLine) throws Exception { String projectName = commandLine.getValue(Options.PROJECT_OPTION); String file = commandLine.getValue(Options.FILE_OPTION); IJavaProject javaProject = JavaUtils.getJavaProject(projectName); ICompilationUnit test = JavaUtils.getCompilationUnit(javaProject, file); ICompilationUnit src = JUnitUtils.findClass(javaProject, test.getTypes()[0]); if (src == null){ return Services.getMessage("junit.testing.class.not.found"); } RefactoringASTParser parser = new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL); CompilationUnit cu = parser.parse(src, true); ITypeBinding base = ASTNodeSearchUtil .getTypeDeclarationNode(src.getTypes()[0], cu).resolveBinding(); this.base.set(base); return super.execute(commandLine); } @Override protected List<IMethodBinding> getOverridableMethods( CompilationUnit cu, ITypeBinding typeBinding) throws Exception { HashSet<String> testMethods = new HashSet<String>(); for (IMethodBinding method : typeBinding.getDeclaredMethods()){ int modifiers = method.getModifiers(); if (!method.isConstructor() && !Modifier.isPrivate(modifiers)) { testMethods.add(method.getName()); } } List<IMethodBinding> testable = new ArrayList<IMethodBinding>(); ITypeBinding objectBinding = cu.getAST().resolveWellKnownType("java.lang.Object"); ITypeBinding parentBinding = base.get(); while (parentBinding != null && !parentBinding.equals(objectBinding)){ for (IMethodBinding method : parentBinding.getDeclaredMethods()){ String name = method.getName(); int modifiers = method.getModifiers(); if (!method.isConstructor() && !Modifier.isPrivate(modifiers) && !testMethods.contains(name)) { testable.add(method); } } parentBinding = parentBinding.getSuperclass(); } return testable; } @Override protected IWorkspaceRunnable getImplOperation( ICompilationUnit src, IType type, Set<String> chosen, IJavaElement sibling, int pos, CommandLine commandLine) throws Exception { RefactoringASTParser parser = new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL); CompilationUnit cu = parser.parse(type.getCompilationUnit(), true); ITypeBinding typeBinding = ASTNodes.getTypeBinding(cu, type); String superType = commandLine.getValue(Options.SUPERTYPE_OPTION); List<IMethodBinding> testable = getOverridableMethods(cu, typeBinding); List<IMethodBinding> tests = new ArrayList<IMethodBinding>(); for (IMethodBinding binding : testable){ ITypeBinding declBinding = binding.getDeclaringClass(); String fqn = declBinding.getQualifiedName().replaceAll("<.*?>", ""); if (fqn.equals(superType) && isChosen(chosen, binding)){ tests.add(binding); } } if (tests.size() > 0){ return new AddTestMethodsOperation( cu, typeBinding, tests.toArray(new IMethodBinding[tests.size()])); } return null; } private class AddTestMethodsOperation implements IWorkspaceRunnable { private CompilationUnit cu; private ITypeBinding typeBinding; private IMethodBinding[] methodBindings; public AddTestMethodsOperation( CompilationUnit cu, ITypeBinding typeBinding, IMethodBinding[] methodBindings) { this.cu = cu; this.typeBinding = typeBinding; this.methodBindings = methodBindings; } @Override @SuppressWarnings("unchecked") public void run(IProgressMonitor monitor) { try{ ICompilationUnit src = (ICompilationUnit)cu.getJavaElement(); IJavaProject javaProject = src.getJavaProject(); MultiTextEdit edit = new MultiTextEdit(); ImportRewrite imports = StubUtility.createImportRewrite(cu, true); imports.addStaticImport("org.junit.Assert", "*", false); imports.addImport(JUnitCorePlugin.JUNIT4_ANNOTATION_NAME); edit.addChild(imports.rewriteImports(null)); AST ast = cu.getAST(); ASTRewrite astRewrite = ASTRewrite.create(ast); ASTNode node = cu.findDeclaringNode(typeBinding); ChildListPropertyDescriptor property = ((AbstractTypeDeclaration)node) .getBodyDeclarationsProperty(); ListRewrite memberRewriter = astRewrite.getListRewrite(node, property); HashSet<String> added = new HashSet<String>(); for (IMethodBinding binding : methodBindings){ String name = binding.getName(); if (added.contains(name)){ continue; } added.add(name); MethodDeclaration stub = ast.newMethodDeclaration(); stub.setConstructor(false); stub.modifiers().addAll(ast.newModifiers(Modifier.PUBLIC)); Annotation marker = ast.newMarkerAnnotation(); marker.setTypeName(ast.newSimpleName("Test")); astRewrite .getListRewrite(stub, MethodDeclaration.MODIFIERS2_PROPERTY) .insertFirst(marker, null); stub.setName(ast.newSimpleName(name)); Block body = ast.newBlock(); stub.setBody(body); String todoTask = ""; String todoTaskTag = JUnitStubUtility.getTodoTaskTag(javaProject); if (todoTaskTag != null) { todoTask = " // " + todoTaskTag; } String message = WizardMessages .NewTestCaseWizardPageOne_not_yet_implemented_string; body.statements().add(astRewrite.createStringPlaceholder( todoTask, ASTNode.RETURN_STATEMENT)); body.statements().add(astRewrite.createStringPlaceholder( Messages.format("fail(\"{0}\");", message), ASTNode.RETURN_STATEMENT)); memberRewriter.insertLast(stub, null); } edit.addChild(astRewrite.rewriteAST()); JavaModelUtil.applyEdit(src, edit, true, null); }catch(Exception e){ throw new RuntimeException(e); } } } }