/******************************************************************************* * Copyright (c) 2009 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.seam.ui.test.ca; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; import org.jboss.tools.common.base.test.contentassist.CATestUtil; import org.jboss.tools.common.el.core.ELCorePlugin; import org.jboss.tools.common.el.core.ca.preferences.ELContentAssistPreferences; import org.jboss.tools.common.util.FileUtil; import org.jboss.tools.jst.web.ui.internal.editor.contentassist.AutoContentAssistantProposal; import org.jboss.tools.jst.jsp.test.ca.ContentAssistantTestCase; import org.jboss.tools.test.util.JobUtils; import org.jboss.tools.test.util.ProjectImportTestSetup; /** * * @author Jeremy * */ public class SeamELContentAssistTestCase extends ContentAssistantTestCase { private static final String PROJECT_NAME = "TestSeamELContentAssist"; private static final String PAGE_NAME = "/WebContent/login.xhtml"; private static final String[] VALID_SEAM_EL_PROPOSALS = new String[] { "TestSeamELContentAssistEntityManagerFactory", "fullPostList", "actor", "applicationContext", "authenticator", "businessProcessContext", "businessProcess", "captcha", "conversationContext", "conversationList", "conversationStack", "conversation", "currentDatetime", "currentDate", "currentTime", "entityManager", "eventContext", "events", "expressions", "facesContext", "facesMessages", "httpError", "identity", "identity:addRole", "identity:addRole(arg0)", "identity:authenticate", "identity:authenticate()", "identity:authenticateMethod", "identity:checkEntityPermission", "identity:checkEntityPermission()", "identity:checkPermission", "identity:checkPermission()", "identity:checkRestriction", "identity:checkRestriction()", "identity:checkRole", "identity:checkRole(role)", "identity:clearDirty", "identity:clearDirty()", "identity:cookieEnabled", "identity:cookieMaxAge", "identity:create", "identity:create()", "identity:hasPermission", "identity:hasPermission()", "identity:hasRole", "identity:hasRole()", "identity:jaasConfigName", "identity:loggedIn", "identity:login", "identity:login()", "identity:logout", "identity:logout()", "identity:password", "identity:principal", "identity:rememberMe", "identity:removeRole", "identity:removeRole()", "identity:subject", "identity:username", "image", "interpolator", "isUserInRole", "jbpmContext", "localeSelector", "locale", "mailSession", "messages", "methodContext", "mockSecureEntity", "org.jboss.seam.captcha.captchaImage", "org.jboss.seam.captcha.captcha", "org.jboss.seam.core.actor", "org.jboss.seam.core.applicationContext", "org.jboss.seam.core.businessProcessContext", "org.jboss.seam.core.businessProcess", "org.jboss.seam.core.conversationContext", "org.jboss.seam.core.conversationEntries", "org.jboss.seam.core.conversationList", "org.jboss.seam.core.conversationStack", "org.jboss.seam.core.conversation", "org.jboss.seam.core.dispatcher", "org.jboss.seam.core.ejb", "org.jboss.seam.core.eventContext", "org.jboss.seam.core.events", "org.jboss.seam.core.exceptions", "org.jboss.seam.core.expressions", "org.jboss.seam.core.facesContext", "org.jboss.seam.core.facesMessages", "org.jboss.seam.core.facesPage", "org.jboss.seam.core.httpError", "org.jboss.seam.core.image", "org.jboss.seam.core.init", "org.jboss.seam.core.interpolator", "org.jboss.seam.core.isUserInRole", "org.jboss.seam.core.jbpmContext", "org.jboss.seam.core.jbpm", "org.jboss.seam.core.localeSelector", "org.jboss.seam.core.locale", "org.jboss.seam.core.manager", "org.jboss.seam.core.messages", "org.jboss.seam.core.methodContext", "org.jboss.seam.core.microcontainer", "org.jboss.seam.core.pageContext", "org.jboss.seam.core.pageflow", "org.jboss.seam.core.pages", "org.jboss.seam.core.persistenceContexts", "org.jboss.seam.core.pojoCache", "org.jboss.seam.core.pooledTaskInstanceList", "org.jboss.seam.core.pooledTask", "org.jboss.seam.core.processInstanceFinder", "org.jboss.seam.core.processInstanceList", "org.jboss.seam.core.processInstance", "org.jboss.seam.core.redirect", "org.jboss.seam.core.renderer", "org.jboss.seam.core.resourceBundle", "org.jboss.seam.core.safeActions", "org.jboss.seam.core.sessionContext", "org.jboss.seam.core.switcher", "org.jboss.seam.core.taskInstanceListForType", "org.jboss.seam.core.taskInstanceList", "org.jboss.seam.core.taskInstance", "org.jboss.seam.core.timeZoneSelector", "org.jboss.seam.core.timeZone", "org.jboss.seam.core.transactionListener", "org.jboss.seam.core.transition", "org.jboss.seam.core.uiComponent", "org.jboss.seam.core.userPrincipal", "org.jboss.seam.core.validation", "org.jboss.seam.core.validators", "org.jboss.seam.debug.contexts", "org.jboss.seam.debug.hotDeployFilter", "org.jboss.seam.debug.introspector", "org.jboss.seam.framework.currentDatetime", "org.jboss.seam.framework.currentDate", "org.jboss.seam.framework.currentTime", "org.jboss.seam.ioc.spring.contextLoader", "org.jboss.seam.ioc.spring.springELResolver", "org.jboss.seam.jms.queueConnection", "org.jboss.seam.jms.queueSession", "org.jboss.seam.jms.topicConnection", "org.jboss.seam.jms.topicSession", "org.jboss.seam.mail.mailSession", "org.jboss.seam.persistence.persistenceProvider", "org.jboss.seam.remoting.messaging.subscriptionRegistry", "org.jboss.seam.remoting.remoting", "org.jboss.seam.security.configuration", "org.jboss.seam.security.identity", "org.jboss.seam.servlet.characterEncodingFilter", "org.jboss.seam.servlet.contextFilter", "org.jboss.seam.servlet.exceptionFilter", "org.jboss.seam.servlet.multipartFilter", "org.jboss.seam.servlet.redirectFilter", "org.jboss.seam.theme.themeSelector", "org.jboss.seam.theme.theme", "org.jboss.seam.ui.entityConverterStore", "org.jboss.seam.ui.entityConverter", "org.jboss.seam.ui.graphicImage.dynamicImageResource", "org.jboss.seam.ui.graphicImage.dynamicImageStore", "org.jboss.seam.ui.resource.webResource", "pageContext", "pageflow", "pojoCache", "pooledTaskInstanceList", "pooledTask", "processInstanceFinder", "processInstanceList", "processInstance", "queueSession", "redirect", "renderer", "resourceBundle", "securityRules", "sessionContext", "switcher", "taskInstanceListForType", "taskInstanceList", "taskInstance", "themeSelector", "theme", "timeZoneSelector", "timeZone", "topicSession", "transition", "uiComponent", "userPrincipal", "validation", "interfaceTest" }; protected void setUp() throws Exception { JobUtils.waitForIdle(); if (project == null) { IResource projectResource = ResourcesPlugin.getWorkspace().getRoot().findMember(PROJECT_NAME); IProject prj = null; if(projectResource == null) { ProjectImportTestSetup setup = new ProjectImportTestSetup( this, "org.jboss.tools.seam.ui.test", "projects/"+PROJECT_NAME, PROJECT_NAME); projectResource = setup.importProject(); } if (projectResource == null) return; prj = projectResource.getProject(); this.project = prj; } JobUtils.waitForIdle(); } /** * Test for https://jira.jboss.org/jira/browse/JBIDE-3213 */ public void testFrameworkComponents() { ELCorePlugin.getDefault().getPreferenceStore().setValue(ELContentAssistPreferences.SHOW_METHODS_WITH_PARENTHESES_ONLY, false); assertTrue("Test project \"" + PROJECT_NAME + "\" is not loaded", (project != null)); checkProposals("/WebContent/frameworkComponents.xhtml", 698, new String[]{"fullPostList.resultList", "fullPostList.next"}, false); } /** * Test for http://jira.jboss.com/jira/browse/JBIDE-1258 */ public void testMessages() { assertTrue("Test project \"" + PROJECT_NAME + "\" is not loaded", (project != null)); checkProposals("/WebContent/messages.xhtml", 494, new String[]{"messages.Text1", "messages.Text2"}, false); // exactly == false, because of current attribute value is also in the proposals list } /** * Test for http://jira.jboss.com/jira/browse/JBIDE-1803 * http://jira.jboss.com/jira/browse/JBIDE-2007 * @throws CoreException */ public void testVarAttributes() throws CoreException { assertTrue("Test project \"" + PROJECT_NAME + "\" is not loaded", (project != null)); IFile component = project.getFile("src/action/demo/TestComponentForVarAttributes.java"); IFile newComponent = project.getFile("src/action/demo/TestComponentForVarAttributes.1"); IFile emptyComponent = project.getFile("src/action/demo/TestComponentForVarAttributes.2"); try{ FileUtil.copyContent(newComponent, component, true, false, new NullProgressMonitor()); project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); checkProposals("/WebContent/varAttributes.xhtml", 458, new String[]{"test.name"}, false); checkProposals("/WebContent/varAttributes.xhtml", 640, new String[]{"item.name"}, false); } finally { FileUtil.copyContent(emptyComponent, component, true, false, new NullProgressMonitor()); project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); } } /** * Do not use this set as is because of colon used instead of dot to separate items of level 2 and more * @return */ protected Set<String> getPageValidProposals() { TreeSet<String> pSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); for (int i = 0; i < VALID_SEAM_EL_PROPOSALS.length; i++) { pSet.add(VALID_SEAM_EL_PROPOSALS[i]); } return pSet; } private int getDotIndex (String expr) { if (expr == null) return 0; int count = 0; int index = 0; while ((index = expr.indexOf('.', index+1)) != -1) { count++; } return count; } private int getValidDotIndex (String expr) { if (expr == null) return 0; int count = 0; int index = 0; while ((index = expr.indexOf(':', index+1)) != -1) { count++; } return count; } protected Set<String> getFilteredProposals(Set<String> proposals, String filter) { TreeSet<String> fSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); if (filter != null) { int dotIndex = getDotIndex(filter); for (String proposal : proposals) { if (getValidDotIndex(proposal) <= dotIndex) { proposal = proposal.replace(':', '.'); if (proposal.startsWith(filter) ) { fSet.add(proposal); } } } } return fSet; } protected Set<String> renewWithPrefixAndPostfix(Set<String> proposals, String prefix, String suffix) { TreeSet<String> rSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); for (String proposal : proposals) { rSet.add(prefix + proposal + suffix); } return rSet; } private int indexOfElBOB (String content, int startFrom) { int index1 = content.indexOf("${", startFrom); int index2 = content.indexOf("#{", startFrom); if (index1 == -1) return index2; if (index2 == -1) return index1; return (index1 < index2 ? index1 : index2); } private List<IRegion> getAttributeValueELRegions(ITextViewer viewer) { List<IRegion> regions = getAttributeValueRegions(viewer); List<IRegion> elRegions = new ArrayList<IRegion>(); String documentContent = document.get(); if (documentContent != null) { for (IRegion r : regions) { int offset = indexOfElBOB(documentContent, r.getOffset()); if (offset != -1 && offset < r.getOffset() + r.getLength()) { elRegions.add(r); } } } return elRegions; } protected List<IRegion> getAttributeValueRegions(ITextViewer viewer) { List<IRegion> regions = new ArrayList<IRegion>(); IDocument document = viewer.getDocument(); int startOffset = 0; int endOffset = document.getLength(); IStructuredDocumentRegion sdRegion = null; while (startOffset < endOffset && (sdRegion = ContentAssistUtils.getStructuredDocumentRegion(viewer, startOffset)) != null) { ITextRegionList list = sdRegion.getRegions(); for (int i = 0; list != null && i < list.size(); i++) { ITextRegion region = list.get(i); if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) { final int regionOffset = sdRegion.getStartOffset() + region.getStart(); final int regionLength = region.getTextLength(); regions.add(new Region (regionOffset,regionLength)); } } startOffset += sdRegion.getLength(); } return regions; } protected List<IRegion> getELRegionsToTest(IDocument document) { List<IRegion> regions = new ArrayList<IRegion>(); String documentContent = document.get(); if (documentContent == null) return regions; int fromIndex = indexOfElBOB(documentContent, 0); while (fromIndex != -1) { int endIndex = documentContent.indexOf("}", fromIndex); final int regionOffset = fromIndex; final int regionLength = (endIndex != -1 ? endIndex - fromIndex : documentContent.length() - fromIndex) + 1; regions.add(new Region (regionOffset,regionLength)); fromIndex = (endIndex != -1 ? indexOfElBOB(documentContent, endIndex) : -1); } return regions; } /** * Test for https://jira.jboss.org/jira/browse/JBIDE-3528 */ public void testInterface() { try { checkProposals("/WebContent/interfaceTest.xhtml", 359, new String[]{"interfaceTest.test.text"}, false); } finally { closeEditor(); } } public void testSeamELContentAssist() { ELCorePlugin.getDefault().getPreferenceStore().setValue(ELContentAssistPreferences.SHOW_METHODS_WITH_PARENTHESES_ONLY, false); openEditor(PAGE_NAME); try { List<IRegion> regionsToTest = getELRegionsToTest(document); if (regionsToTest != null && regionsToTest.size() >= 1) { // for (IRegion region : regionsToTest) { IRegion region = regionsToTest.get(0); try { // System.out.println("Seam EL Region To Test: [" + region.getOffset() + "/" + region.getLength() + "] ==> [" + // document.get(region.getOffset(), region.getLength()) + "]"); int startOffset = region.getOffset() + 2; for (int i = 2; i < region.getLength(); i++) { int offset = region.getOffset() + i; String filter = document.get(startOffset, offset - startOffset); Set<String> filteredValidProposals = getFilteredProposals(getPageValidProposals(), filter); ICompletionProposal[] result= null; String errorMessage = null; List<ICompletionProposal> res = CATestUtil.collectProposals(contentAssistant, viewer, offset); assertTrue("Content Assist returned no proposals: ", (res != null && res.size() > 0)); // if (errorMessage != null && errorMessage.trim().length() > 0) { // System.out.println("#" + offset + ": ERROR MESSAGE: " + errorMessage); // } // compare SeamELCompletionProposals in the result to the filtered valid proposals Set<String> existingProposals = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); for (ICompletionProposal p : res) { // System.out.println("Result#" + i + "-" + j + " ==> " + result[j].getClass().getName()); // Cannot separate Seam EL proposals from all the others, // so check only the required proposals existance // if (p instanceof AutoContentAssistantProposal) { AutoContentAssistantProposal proposal = (AutoContentAssistantProposal)p; String proposalString = proposal.getReplacementString(); if (filteredValidProposals.contains(proposalString)) { existingProposals.add(proposalString); filteredValidProposals.remove(proposalString); } else { String validProposal = null; if (proposalString.indexOf("(") > -1) { String methodName = proposalString.substring(0, proposalString.indexOf("(")).trim(); // Find method with the same name in filtered valid proposals for (String valid : filteredValidProposals) { if (valid.indexOf("(") > -1) { String validName = valid.substring(0, valid.indexOf("(")).trim(); if (methodName.equals(validName)) { validProposal = valid; break; } } } } if (validProposal != null) { existingProposals.add(validProposal); filteredValidProposals.remove(validProposal); } } } } StringBuilder sb = new StringBuilder("{"); for (String string : filteredValidProposals) { sb.append(string).append(','); } sb.append('}'); assertTrue("Some Seam EL proposals werent\'t shown in the Content Assistant: " + sb.toString(), filteredValidProposals.isEmpty()); } } catch (BadLocationException e) { assertNull("An exception caught: " + (e != null? e.getMessage() : ""), e); } // } } regionsToTest = getAttributeValueELRegions(viewer); if (regionsToTest != null && regionsToTest.size() >= 1) { // for (IRegion region : regionsToTest) { IRegion region = regionsToTest.get(0); try { // System.out.println("Attribute Region To Test: [" + region.getOffset() + "/" + region.getLength() + "] ==> [" + // document.get(region.getOffset(), region.getLength()) + "]"); String attributeText = document.get(region.getOffset(), region.getLength()); int openQuoteIndex = attributeText.indexOf('"'); if (openQuoteIndex == -1) openQuoteIndex = attributeText.indexOf('\''); else { int openQuoteIndex2 = attributeText.indexOf('\''); if (openQuoteIndex2 != -1) { openQuoteIndex = (openQuoteIndex < openQuoteIndex2 ? openQuoteIndex : openQuoteIndex2); } } int closeQuoteIndex = (openQuoteIndex == -1 ? -1 : attributeText.lastIndexOf(attributeText.charAt(openQuoteIndex))); int startOffset = region.getOffset(); for (int i = 0; i < region.getLength(); i++) { int offset = startOffset + i; if ((openQuoteIndex != -1 && i <= openQuoteIndex) || (closeQuoteIndex != -1 && i >= closeQuoteIndex)) { // - Before and at opening quotation mark (single or double quote) // - or at and after closing quotation mark (single or double quote) // There is no prompting acceptable } else { String filter = document.get(startOffset + openQuoteIndex + 1, offset - startOffset - openQuoteIndex - 1); String clearedFilter = filter; if (filter.startsWith("#{")) { clearedFilter = filter.substring(2); } else { continue; // We're not interested in non-EL proposals } Set<String> filteredValidProposals = getFilteredProposals(getPageValidProposals(), clearedFilter); ICompletionProposal[] result= null; String errorMessage = null; List<ICompletionProposal> res = CATestUtil.collectProposals(contentAssistant, viewer, offset); assertTrue("Content Assist returned no proposals: ", (res != null && res.size() > 0)); // if (errorMessage != null && errorMessage.trim().length() > 0) { // System.out.println("#" + offset + ": ERROR MESSAGE: " + errorMessage); // } // compare SeamELCompletionProposals in the result to the filtered valid proposals Set<String> existingProposals = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); for (ICompletionProposal p : res) { // System.out.println("Result#" + i + "/" + j + " ==> " + result[j].getClass().getName()); // Cannot separate Seam EL proposals from all the others, // so check only the required proposals existance // if (p instanceof AutoContentAssistantProposal) { AutoContentAssistantProposal proposal = (AutoContentAssistantProposal)p; String proposalString = proposal.getReplacementString(); if (filteredValidProposals.contains(proposalString)) { existingProposals.add(proposalString); filteredValidProposals.remove(proposalString); } else { String validProposal = null; if (proposalString.indexOf("(") > -1) { String methodName = proposalString.substring(0, proposalString.indexOf("(")).trim(); // Find method with the same name in filtered valid proposals for (String valid : filteredValidProposals) { if (valid.indexOf("(") > -1) { String validName = valid.substring(0, valid.indexOf("(")).trim(); if (methodName.equals(validName)) { validProposal = valid; break; } } } } if (validProposal != null) { existingProposals.add(validProposal); filteredValidProposals.remove(validProposal); } } } } assertTrue("Some in-attribute Seam EL proposals werent\'t shown in the Content Assistant", filteredValidProposals.isEmpty()); } } } catch (BadLocationException e) { e.printStackTrace(); assertNull("An exception caught: " + (e != null? e.getMessage() : ""), e); } // } } } finally { closeEditor(); } } private static final String PAGE_HOME_NAME = "/WebContent/home.xhtml"; public void testContentAssistForInvocationOnString() { openEditor(PAGE_HOME_NAME); try { List<IRegion> regionsToTest = getELRegionsToTest(document); if (regionsToTest != null) { for (IRegion region : regionsToTest) { int startOffset = region.getOffset() + 2; int offset = startOffset + 10; String errorMessage = null; List<ICompletionProposal> res = CATestUtil.collectProposals(contentAssistant, viewer, offset); assertNotNull("Proposals were not created.", res); assertEquals("Incorrect number of proposals for #{'aa'.subst|ring(1)}", 3, res.size()); } } } finally { closeEditor(); } } }