| /******************************************************************************* |
| * Copyright (c) 2006 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.xml.ui.tests; |
| |
| import java.io.ByteArrayInputStream; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import junit.framework.TestCase; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IProjectDescription; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.core.runtime.content.IContentType; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.text.reconciler.IReconciler; |
| import org.eclipse.jface.text.source.SourceViewerConfiguration; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.ide.IDE; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.eclipse.wst.sse.ui.StructuredTextEditor; |
| import org.eclipse.wst.sse.ui.internal.SSEUIPlugin; |
| import org.eclipse.wst.sse.ui.internal.provisional.preferences.CommonEditorPreferenceNames; |
| import org.eclipse.wst.sse.ui.internal.reconcile.DocumentRegionProcessor; |
| import org.eclipse.wst.sse.ui.internal.reconcile.validator.ValidatorMetaData; |
| import org.eclipse.wst.sse.ui.internal.reconcile.validator.ValidatorStrategy; |
| |
| /** |
| * Tests reconciler in an open editor. The location of this class is awkward |
| * in that it refers to content types declared in plugins that aren't required |
| * to be present. |
| */ |
| public class TestSourceValidationFramework extends TestCase { |
| /** |
| * THIS SUBCLASS IS FOR TESTING ONLY |
| */ |
| public static class TestStructuredTextEditor extends StructuredTextEditor { |
| public SourceViewerConfiguration textViewerConfiguration = null; |
| |
| protected void setSourceViewerConfiguration(SourceViewerConfiguration config) { |
| super.setSourceViewerConfiguration(config); |
| textViewerConfiguration = config; |
| } |
| } |
| |
| private static final String PROJECT_NAME = "TestSourceValidationFramework"; |
| |
| private static final String SEPARATOR = String.valueOf(IPath.SEPARATOR); |
| |
| private boolean fPreviousReconcilerPref; |
| |
| public TestSourceValidationFramework() { |
| super("TestSourceValidationFramework"); |
| } |
| |
| private IFile ensureFileIsAccessible(String filePath, byte[] contents) { |
| IFile blankFile = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(filePath)); |
| if (blankFile != null && !blankFile.isAccessible()) { |
| try { |
| byte[] bytes = contents; |
| if (bytes == null) { |
| bytes = new byte[0]; |
| } |
| blankFile.create(new ByteArrayInputStream(bytes), true, new NullProgressMonitor()); |
| } |
| catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } |
| return blankFile; |
| } |
| |
| private IContentType[] detectContentTypes(String fileName) { |
| IContentType[] types = null; |
| IFile file = ensureFileIsAccessible(PROJECT_NAME + SEPARATOR + fileName, null); |
| |
| types = Platform.getContentTypeManager().findContentTypesFor(file.getName()); |
| if (types.length == 0) { |
| IContentDescription d = null; |
| try { |
| // optimized description lookup, might not succeed |
| d = file.getContentDescription(); |
| if (d != null) { |
| types = new IContentType[]{d.getContentType()}; |
| } |
| } |
| catch (CoreException e) { |
| /* |
| * should not be possible given the accessible and file type |
| * check above |
| */ |
| } |
| } |
| if (types == null) { |
| types = Platform.getContentTypeManager().findContentTypesFor(file.getName()); |
| } |
| return types; |
| } |
| |
| private String[] detectContentTypeIDs(String fileName) { |
| IContentType[] types = detectContentTypes(fileName); |
| String[] ids = new String[types.length]; |
| for (int i = 0; i < types.length; i++) { |
| ids[i] = types[i].getId(); |
| } |
| return ids; |
| } |
| |
| private boolean identicalContents(Object o1[], Object o2[]) { |
| if (o1.length == 0 && o2.length == 0) |
| return true; |
| |
| Object[] array1 = new Object[o1.length]; |
| Object[] array2 = new Object[o2.length]; |
| System.arraycopy(o1, 0, array1, 0, o1.length); |
| System.arraycopy(o2, 0, array2, 0, o2.length); |
| Arrays.sort(array1); |
| Arrays.sort(array2); |
| return Arrays.equals(array1, array2); |
| } |
| |
| |
| private void ensureProjectIsAccessible(String projName) { |
| IProjectDescription description = ResourcesPlugin.getWorkspace().newProjectDescription(projName); |
| |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projName); |
| try { |
| if (!project.exists()) |
| project.create(description, new NullProgressMonitor()); |
| if (!project.isAccessible()) |
| project.open(new NullProgressMonitor()); |
| } |
| catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| private List getSourceValidatorIDs(String fileName) throws Exception { |
| List validatorIds = new ArrayList(1); |
| IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); |
| IWorkbenchPage page = workbenchWindow.getActivePage(); |
| |
| IFile file = ensureFileIsAccessible(PROJECT_NAME + SEPARATOR + fileName, null); |
| IEditorPart editor = IDE.openEditor(page, file, TestStructuredTextEditor.class.getName(), true); |
| |
| ITextEditor textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class); |
| TestStructuredTextEditor testTextEditor = (TestStructuredTextEditor) textEditor; |
| IReconciler reconciler = testTextEditor.textViewerConfiguration.getReconciler(testTextEditor.getTextViewer()); |
| |
| assertNotNull(reconciler); |
| assertTrue("unexpected IReconciler implementation: " + reconciler.getClass(), reconciler instanceof DocumentRegionProcessor); |
| |
| Class reconcilerClass = reconciler.getClass(); |
| Method method = null; |
| while (reconcilerClass != Object.class && method == null) { |
| Method[] methods = reconcilerClass.getDeclaredMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| if (methods[i].getName().equals("getValidatorStrategy")) { |
| method = methods[i]; |
| } |
| } |
| reconcilerClass = reconcilerClass.getSuperclass(); |
| } |
| |
| assertNotNull("no getValidatorStrategy method found on " + reconciler.getClass(), method); |
| method.setAccessible(true); |
| ValidatorStrategy strategy = (ValidatorStrategy) method.invoke(reconciler, new Object[0]); |
| assertNotNull(strategy); |
| Field fMetaData = strategy.getClass().getDeclaredField("fMetaData"); |
| assertNotNull("validator metadata field \"fMetaData\" not found on strategy " + strategy.getClass(), fMetaData); |
| fMetaData.setAccessible(true); |
| List metadata = (List) fMetaData.get(strategy); |
| assertNotNull(metadata); |
| for (int i = 0; i < metadata.size(); i++) { |
| validatorIds.add(((ValidatorMetaData) metadata.get(i)).getValidatorId()); |
| } |
| |
| page.closeEditor(editor, false); |
| |
| return validatorIds; |
| } |
| |
| protected void setUp() throws Exception { |
| ensureProjectIsAccessible(PROJECT_NAME); |
| |
| // turn on reconciling |
| IPreferenceStore store = SSEUIPlugin.getDefault().getPreferenceStore(); |
| fPreviousReconcilerPref = store.getBoolean(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS); |
| if (!fPreviousReconcilerPref) { |
| store.setValue(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS, true); |
| } |
| } |
| |
| protected void tearDown() throws Exception { |
| // restore reconciling preference |
| IPreferenceStore store = SSEUIPlugin.getDefault().getPreferenceStore(); |
| store.setValue(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS, fPreviousReconcilerPref); |
| } |
| |
| public void testSourceValidationEnablementWithInheritedValidators() throws Exception { |
| Object[] xmlValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.xml").toArray(); |
| assertTrue("No XML source validators found", xmlValidatorIDs.length > 0); |
| Object[] xml99ValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.xml99").toArray(); |
| assertTrue("No XML99 source validators found", xml99ValidatorIDs.length > 0); |
| |
| Arrays.sort(xmlValidatorIDs); |
| Arrays.sort(xml99ValidatorIDs); |
| |
| assertEquals("validator lists should be the same length", xmlValidatorIDs.length, xml99ValidatorIDs.length); |
| for (int i = 0; i < xmlValidatorIDs.length; i++) { |
| assertEquals("validator IDs should be the same [" + i + "]", xmlValidatorIDs[i], xml99ValidatorIDs[i]); |
| } |
| } |
| |
| public void testSourceValidationEnablementWithUniqueValidators() throws Exception { |
| String[] xmlContentTypes = detectContentTypeIDs("testValidatorConfigurations.xml"); |
| String[] xsdContentTypes = detectContentTypeIDs("testValidatorConfigurations.xsd"); |
| |
| /* |
| * If the current configuration does not include a distinct XSD |
| * content type, skip the rest |
| */ |
| if (!identicalContents(xmlContentTypes, xsdContentTypes)) { |
| List xmlValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.xml"); |
| assertTrue("No XML source validators found", !xmlValidatorIDs.isEmpty()); |
| List xsdValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.xsd"); |
| assertTrue("No XSD source validators found", !xsdValidatorIDs.isEmpty()); |
| for (int i = 0; i < xmlValidatorIDs.size(); i++) { |
| assertTrue("XML Validator found on XSD input", !xsdValidatorIDs.contains(xmlValidatorIDs.get(i))); |
| } |
| } |
| else { |
| String message = "No distinct XSD content type found while running " + getClass().getName(); |
| System.err.println(message); |
| Logger.log(Logger.WARNING, message); |
| } |
| } |
| |
| public void testSourceValidationEnablementWithUnrelatedContentTypes() throws Exception { |
| String[] dtdContentTypes = detectContentTypeIDs("testValidatorConfigurations.dtd"); |
| String[] jspContentTypes = detectContentTypeIDs("testValidatorConfigurations.jsp"); |
| if (dtdContentTypes.length == 0) { |
| String message = "No DTD content type found while running " + getClass().getName(); |
| System.err.println(message); |
| Logger.log(Logger.WARNING, message); |
| } |
| if (jspContentTypes.length == 0) { |
| String message = "No JSP content type found while running " + getClass().getName(); |
| System.err.println(message); |
| Logger.log(Logger.WARNING, message); |
| } |
| |
| |
| if (dtdContentTypes.length > 0 && jspContentTypes.length > 0 && !identicalContents(dtdContentTypes, jspContentTypes)) { |
| List dtdValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.dtd"); |
| assertTrue("No DTD source validators found", !dtdValidatorIDs.isEmpty()); |
| List jspValidatorIDs = getSourceValidatorIDs("testValidatorConfigurations.jsp"); |
| assertTrue("No JSP source validators found", !jspValidatorIDs.isEmpty()); |
| int dtdValidatorCount = dtdValidatorIDs.size(); |
| dtdValidatorIDs.removeAll(jspValidatorIDs); |
| assertEquals("validators found running on both CSS and DTD", dtdValidatorCount, dtdValidatorIDs.size()); |
| } |
| } |
| } |