/******************************************************************************* * Copyright (c) 2012 VMWare, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMWare, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.refactoring.test; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameFieldProcessor; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameMethodProcessor; import org.eclipse.jdt.internal.corext.refactoring.rename.RenameVirtualMethodProcessor; import org.eclipse.jdt.internal.corext.util.Strings; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring; import org.grails.ide.eclipse.core.model.GrailsVersion; import org.grails.ide.eclipse.ui.internal.importfixes.GrailsProjectVersionFixer; import org.springsource.ide.eclipse.commons.tests.util.StsTestUtil; /** * @author Kris De Volder * @since 2.8 */ public class GrailsActionRenameTest extends GrailsRefactoringTest { @Override protected void setUp() throws Exception { super.setUp(); //clearGrailsState(); ensureDefaultGrailsVersion(GrailsVersion.MOST_RECENT); GrailsProjectVersionFixer.globalAskToConvertToGrailsProjectAnswer = true; } @Override protected void tearDown() throws Exception { super.tearDown(); if (undo!=null) { undoLastRefactoring(); //Return the test project to original state } } // public void testImportGtunes() throws Exception { // ensureDefaultGrailsVersion(GrailsVersion.MOST_RECENT); // importZippedProject("gTunez"); // // ///////////////////////////////////////////////////////////////////////////////////////////////// // //Check a few things about this test project // checkImportedProject(); // } public void testPerformRenameMethodRefactoring() throws Exception { if (GrailsVersion.MOST_RECENT.isSnapshot()) { //Don't run for snapshots, too much work to create test projects for moving target return; } if (GrailsVersion.getDefault().compareTo(GrailsVersion.V_2_0_0)>=0) { //This test is only valid for Grails 2.0 where controller actions are methods importZippedProject("gTunez"); checkImportedProject(); createResource(project, "grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index() { \n" + " redirect(action:\"list\")\n" + " }\n" + " \n" + " def list() {\n" + " redirect(action:\"list\", controller: \"song\")\n" + " }\n" + "}\n"); StsTestUtil.assertNoErrors(project); // This forces a build as well... String oldActionName = "list"; String newActionName = "catalog"; IType controller = getType("gtunez.SongController"); IMethod target = getMethod(controller, "list"); // controller.getMethod(oldActionName, new String[] {}); assertTrue("Method doesn't exist: ", target.exists()); RenameMethodProcessor processor = new RenameVirtualMethodProcessor(target); processor.setNewElementName(newActionName); RenameRefactoring refactoring = new RenameRefactoring(processor); RefactoringStatus status = performRefactoring(refactoring, true, false); assertOK(status); // Now check whether the all the changes we think are supposed to happen did happen. //The gsp file was renamed? assertFileDeleted("/gTunez/grails-app/views/song/"+oldActionName+".gsp"); assertFile("/gTunez/grails-app/views/song/"+newActionName+".gsp"); //TODO: contents of the file! assertFile("/gTunez/grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index() { \n" + " redirect(action:\"list\")\n" + " }\n" + " \n" + " def list() {\n" + " redirect(action:\"catalog\", controller: \"song\")\n" + " }\n" + "}\n"); String songControllerPath = "/gTunez/grails-app/controllers/gtunez/SongController.groovy"; String songController = getContents(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(songControllerPath))); songController = songController.replace('"'+oldActionName+'"', '"'+newActionName+'"'); songController = songController.replace("def "+oldActionName, "def "+newActionName); assertFile(songControllerPath, songController); } } private IMethod getMethod(IType controller, String name) throws JavaModelException { IMethod[] methods = controller.getMethods(); for (IMethod m : methods) { if (m.getElementName().equals(name)) { return m; } } return null; } /** * It is possible to have controller without associated views. This shouldn't break the refactoring. */ public void testPerformRenameActionWithoutViewRefactoring() throws Exception { if (GrailsVersion.MOST_RECENT.isSnapshot()) { //Don't run for snapshots, too much work to create test projects for moving target return; } importZippedProject("gTunez"); checkImportedProject(); createResource(project, "grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index() { \n" + " redirect(action:\"list\")\n" + " }\n" + " \n" + " def list() {\n" + " redirect(action:\"list\", controller: \"song\")\n" + " }\n" + "}\n"); StsTestUtil.assertNoErrors(project); // This forces a build as well... String oldActionName = "list"; String newActionName = "catalog"; IType controller = getType("gtunez.ExtraController"); IMethod target = controller.getMethod(oldActionName, new String[] {}); RenameMethodProcessor processor = new RenameVirtualMethodProcessor(target); processor.setNewElementName(newActionName); RenameRefactoring refactoring = new RenameRefactoring(processor); RefactoringStatus status = performRefactoring(refactoring, true, false); assertOK(status); //Check changes assertFile("/gTunez/grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index() { \n" + " redirect(action:\"catalog\")\n" + " }\n" + " \n" + " def catalog() {\n" + " redirect(action:\"list\", controller: \"song\")\n" + " }\n" + "}\n"); String songControllerPath = "/gTunez/grails-app/controllers/gtunez/SongController.groovy"; String songController = getContents(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(songControllerPath))); assertFile(songControllerPath, songController); } /** * This test uses actions represented as fields (1.3.x style). To see if these actions also get * visited and renamed properly. */ public void testPerformFieldActionRefactoring() throws Exception { if (GrailsVersion.MOST_RECENT.isSnapshot()) { //Don't run for snapshots, too much work to create test projects for moving target return; } importZippedProject("gTunez"); checkImportedProject(); createResource(project, "grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index = { \n" + " redirect(action:\"list\")\n" + " }\n" + " \n" + " def list = {\n" + " redirect(action:\"list\", controller: \"song\")\n" + " }\n" + "}\n"); String oldActionName = "list"; String newActionName = "catalog"; createResource(project, "grails-app/views/extra/"+oldActionName+".gsp", "<%@ page import=\"gtunez.Song\" %>\n" + "<!doctype html>\n" + "<html>\n" + " <head>\n" + " <meta name=\"layout\" content=\"main\">\n" + " <g:set var=\"entityName\" value=\"${message(code: 'song.label', default: 'Banana')}\" />\n" + " <title><g:message code=\"default.list.label\" args=\"[entityName]\" /></title>\n" + " </head>\n" + " <body>\n" + " <h1>A few links:</h1>\n" + " <g:link action=\"list\" id=\"1\">blah</g:link>\n" + " <g:link action=\"show\" id=\"${currentBook.id}\">blah</g:link>\n" + " <g:link controller=\"book\">Book Home</g:link>\n" + " <g:link controller=\"book\" action=\"list\">blah</g:link>\n" + " <g:link controller=\"extra\">Book Home</g:link>\n" + " <g:link controller=\"extra\" action=\"list\">blah</g:link>\n" + " <g:link controller=\"extra\" action=\"show\">blah</g:link>\n" + " </body>\n" + "</html>\n"); StsTestUtil.assertNoErrors(project); // This forces a build as well... IType controller = getType("gtunez.ExtraController"); IField target = controller.getField(oldActionName); RenameFieldProcessor processor = new RenameFieldProcessor(target); processor.setNewElementName(newActionName); RenameRefactoring refactoring = new RenameRefactoring(processor); RefactoringStatus status = performRefactoring(refactoring, true, false); assertOK(status); // Now check whether the changes we think are supposed to happen did happen. //The gsp file was renamed? assertFileDeleted("/gTunez/grails-app/views/extra/"+oldActionName+".gsp"); assertFile("/gTunez/grails-app/views/extra/"+newActionName+".gsp", "<%@ page import=\"gtunez.Song\" %>\n" + "<!doctype html>\n" + "<html>\n" + " <head>\n" + " <meta name=\"layout\" content=\"main\">\n" + " <g:set var=\"entityName\" value=\"${message(code: 'song.label', default: 'Banana')}\" />\n" + " <title><g:message code=\"default.list.label\" args=\"[entityName]\" /></title>\n" + " </head>\n" + " <body>\n" + " <h1>A few links:</h1>\n" + " <g:link action=\"catalog\" id=\"1\">blah</g:link>\n" + " <g:link action=\"show\" id=\"${currentBook.id}\">blah</g:link>\n" + " <g:link controller=\"book\">Book Home</g:link>\n" + " <g:link controller=\"book\" action=\"list\">blah</g:link>\n" + " <g:link controller=\"extra\">Book Home</g:link>\n" + " <g:link controller=\"extra\" action=\"catalog\">blah</g:link>\n" + " <g:link controller=\"extra\" action=\"show\">blah</g:link>\n" + " </body>\n" + "</html>\n"); assertFile("/gTunez/grails-app/controllers/gtunez/ExtraController.groovy", "package gtunez\n" + "\n" + "class ExtraController {\n" + "\n" + " def index = { \n" + " redirect(action:\"catalog\")\n" + " }\n" + " \n" + " def catalog = {\n" + " redirect(action:\"list\", controller: \"song\")\n" + " }\n" + "}\n"); String songControllerPath = "/gTunez/grails-app/controllers/gtunez/SongController.groovy"; String songController = getContents(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(songControllerPath))); //songController has only references to its own actions so renaming an action in the extra controller should leave it unchanged assertFile(songControllerPath, songController); } private void assertOK(RefactoringStatus status) { if (!status.isOK()) { fail(status.getEntryWithHighestSeverity().getMessage()); } } /** * Line-based version of junit.framework.Assert.assertEquals(String, String) * without considering line delimiters. * @param expected the expected value * @param actual the actual value */ public static void assertEqualLines(String expected, String actual) { assertEqualLines("", expected, actual); } /** * Line-based version of junit.framework.Assert.assertEquals(String, String, String) * without considering line delimiters. * @param message the message * @param expected the expected value * @param actual the actual value */ public static void assertEqualLines(String message, String expected, String actual) { String[] expectedLines= Strings.convertIntoLines(expected); String[] actualLines= Strings.convertIntoLines(actual); String expected2= (expectedLines == null ? null : Strings.concatenate(expectedLines, "\n")); String actual2= (actualLines == null ? null : Strings.concatenate(actualLines, "\n")); assertEquals(message, expected2, actual2); } }