/******************************************************************************* * 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.test.gsp; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.sse.ui.internal.StructuredTextViewer; import org.eclipse.wst.sse.ui.internal.contentassist.CompletionProposalComputerRegistry; import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal; import org.grails.ide.eclipse.editor.gsp.configuration.GSPViewerConfiguration; import org.grails.ide.eclipse.test.GrailsTestsActivator; /** * * @author Andrew Eisenberg * @since 2.8.0 */ public class GSPContentAssistTests extends AbstractGSPTagsTest { private static final String FLAR_CONTROLLER_2_0_0 = "def flar = { }"; private static final String FLAR_CONTROLLER_1_3_7 = "def flar() { }"; private static final String SOME_CONTROLLER_2_0_0 = "def some = { [ first : 1, second : [1] ] }"; private static final String SOME_CONTROLLER_1_3_7 = "def some() { [ first : 1, second : [1] ] }"; @Override protected void setUp() throws Exception { super.setUp(); // ensure that proposal categories are initialized CompletionProposalComputerRegistry.getDefault().getProposalCategories(); } public void testControllerActionsReturn1() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(SOME_CONTROLLER_1_3_7); } else { createController(SOME_CONTROLLER_2_0_0); } doTest("${f}", "${first}", "first", "${f}".indexOf('}')); } public void testControllerActionsReturn2() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(SOME_CONTROLLER_1_3_7); } else { createController(SOME_CONTROLLER_2_0_0); } doTest("${s}", "${second}", "second", "${s}".indexOf('}')); } public void testControllerActionsReturn3() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(SOME_CONTROLLER_1_3_7); } else { createController(SOME_CONTROLLER_2_0_0); } doTest("${first.do}", "${first.doubleValue()}", "doubleValue", "${first.do}".indexOf('}')); } public void testControllerActionsLink1() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(FLAR_CONTROLLER_1_3_7); } else { createController(FLAR_CONTROLLER_2_0_0); } String initial = "<html><body><g:link controller=\"\"></g:link></body></html>"; String expected = initial.replace("\"\"", "\"nuthin\""); doTest(initial, expected, "nuthin", initial.indexOf("\">")); } public void testControllerActionsLink2() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(FLAR_CONTROLLER_1_3_7); } else { createController(FLAR_CONTROLLER_2_0_0); } String initial = "<html><body><g:link controller=\"nuthin\" action=\"\"></g:link></body></html>"; String expected = initial.replace("\"\"", "\"flar\""); doTest(initial, expected, "flar", initial.indexOf("\">")); } public void testControllerActionsLink3() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(FLAR_CONTROLLER_1_3_7); } else { createController(FLAR_CONTROLLER_2_0_0); } String initial = "<html><body><g:link action=\"\" controller=\"nuthin\"></g:link></body></html>"; String expected = initial.replace("\"\"", "\"flar\""); doTest(initial, expected, "flar", initial.indexOf("\" ")); } public void testControllerActionsLink4() throws Exception { if (GrailsTestsActivator.isGrails200OrLater()) { createController(FLAR_CONTROLLER_1_3_7); } else { createController(FLAR_CONTROLLER_2_0_0); } String initial = "<html><body><g:link action=\"\"></g:link></body></html>"; String expected = initial.replace("\"\"", "\"flar\""); doTest(initial, expected, "flar", initial.indexOf("\">")); } public void testSimple() throws Exception { doTest("", "<html></html>", "html", 0); } public void testBuiltInGsp1() throws Exception { doTest("<html><body></body></html>", "<html><body><g:if></g:if></body></html>", "g:if"); } public void testBuiltInGsp2() throws Exception { doTest("<html><body></body></html>", "<html><body><g:set></g:set></body></html>", "g:set"); } // standard tag libs not being found since there is // no source code for the grails jars public void _testStandardGsp1() throws Exception { doTest("<html><body></body></html>", "<html><body><g:field type=\"\"/></body></html>", "g:field"); } public void testCustomGsp1() throws Exception { createTagLib("static namespace = 'nuthin'\n" + "def foo = { }"); doTest("<html><body></body></html>", "<html><body><nuthin:foo/></body></html>", "nuthin:foo"); } public void testCustomGsp2() throws Exception { createTagLib("static namespace = 'nuthin'\n" + "def foo = { attrs, body -> }"); doTest("<html><body></body></html>", "<html><body><nuthin:foo></nuthin:foo></body></html>", "nuthin:foo"); } public void testCustomGsp3() throws Exception { createTagLib("static namespace = 'nuthin'\n" + "/**\n* @attr attr1 REQUIRED some stuff */\ndef foo = { attrs, body -> }"); doTest("<html><body></body></html>", "<html><body><nuthin:foo attr1=\"\"></nuthin:foo></body></html>", "nuthin:foo"); } public void testInScriptlet1() throws Exception { String contents = "<html><body>${f}</body></html>"; int location = contents.indexOf('}')-1; doTest(contents, contents.replace("${f}", "${flash}"), "flash", location); } public void testInScriptlet2() throws Exception { String contents = "<html><body>${application.}</body></html>"; int location = contents.indexOf('}'); doTest(contents, contents.replace("${application.}", "${application.minorVersion}"), "minorVersion", location); } public void testInScriptletDef() throws Exception { String contents = "<html><body><g:def var=\"foo\" value=\"\"/>${f}</body></html>"; int location = contents.indexOf('}'); doTest(contents, contents.replace("${f}", "${foo}"), "foo", location); } public void testInScriptletSet() throws Exception { String contents = "<html><body><g:set var=\"foo\" value=\"\"/>${f}</body></html>"; int location = contents.indexOf('}'); doTest(contents, contents.replace("${f}", "${foo}"), "foo", location); } public void testInScriptletInferencing() throws Exception { String contents = "<html><body>${def x = 9\n9.do}</body></html>"; int location = contents.indexOf('}'); doTest(contents, contents.replace("9.do", "9.doubleValue()"), "doubleValue", location); } public void testInScriptletCreateImport() throws Exception { String contents = "<html><body>${HT}</body></html>"; String newContents = "<%@page import=\"javax.swing.text.html.HTML\"%>\n" + "<html><body>${HTML}</body></html>"; int location = contents.indexOf('}'); doTest(contents, newContents, "HTML", location); } private void doTest(String initial, String expected, String proposalToFind) throws Exception { doTest(initial, expected, proposalToFind, -1); } private void doTest(String initial, String expected, String proposalToFind, int location) throws Exception { if (location == -1) { location = initial.indexOf("</body></html>"); } StructuredTextViewer viewer = setUpViewer(initial); ICompletionProposal[] proposals = performContentAssist(viewer, location); ICompletionProposal proposal = findProposal(proposalToFind, proposals); assertProposalApplication(viewer, expected, proposal); tearDownViewer(viewer); } private ICompletionProposal[] performContentAssist(StructuredTextViewer viewer, int location) throws Exception { GSPViewerConfiguration configuration = new GSPViewerConfiguration(); viewer.configure(configuration); IContentAssistant contentAssistant = configuration.getContentAssistant(viewer); contentAssistant.install(viewer); String contentType = TextUtilities.getContentType(viewer.getDocument(), "org.eclipse.wst.sse.core.default_structured_text_partitioning", location, true); ICompletionProposal[] proposals = contentAssistant.getContentAssistProcessor(contentType).computeCompletionProposals(viewer, location); contentAssistant.uninstall(); return proposals; } private ICompletionProposal findProposal(String expectedProposalText, ICompletionProposal[] proposals) { for (ICompletionProposal proposal : proposals) { if (proposal.getDisplayString().startsWith(expectedProposalText)) { return proposal; } } fail("Did not find expected proposal: " + expectedProposalText + "\nInstead found:\n" + printProposals(proposals)); return null; } /** * @param proposals * @return */ private String printProposals(ICompletionProposal[] proposals) { StringBuilder sb = new StringBuilder(); for (ICompletionProposal proposal : proposals) { sb.append(proposal.getDisplayString() + "\n"); } return sb.toString(); } private void assertProposalApplication(StructuredTextViewer viewer, String expected, ICompletionProposal proposal) { if (proposal instanceof CustomCompletionProposal) { ((CustomCompletionProposal) proposal).apply(viewer, '\0', 0, 0); assertEquals("Invalid proposal application", expected, viewer.getDocument().get()); } else { IDocument document = viewer.getDocument(); proposal.apply(document); assertEquals("Invalid proposal application", expected, document.get()); } } private StructuredTextViewer setUpViewer(String contents) throws Exception { IStructuredModel scratchModel = createModel("grails-app/views/nuthin/some.gsp", contents); StructuredTextViewer viewer = new StructuredTextViewer(new Shell(), null, null, false, SWT.NONE); viewer.setDocument(scratchModel.getStructuredDocument()); return viewer; } private void tearDownViewer(StructuredTextViewer viewer) { viewer.getTextWidget().getShell().dispose(); } }