/******************************************************************************* * Copyright (c) 2012-2013 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 * * Contributor: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.base.test.validation; import java.util.Iterator; import junit.framework.TestCase; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; import org.jboss.tools.test.util.JobUtils; import org.jboss.tools.test.util.WorkbenchUtils; /** * * @author Victor V. Rubezhny * */ public abstract class AbstractAsYouTypeValidationTest extends TestCase { public static final int MAX_SECONDS_TO_WAIT = 5; protected String fileName; protected IProject project = null; protected IEditorPart editorPart = null; protected ITextEditor textEditor = null; protected ISourceViewer viewer = null; protected IDocument document = null; protected IFile file = null; IAnnotationModel annotationModel = null; public static final String EL2FIND_START = "#{"; public static final String EL2FIND_END = "}"; public AbstractAsYouTypeValidationTest(IProject project) { this.project = project; } public AbstractAsYouTypeValidationTest() { } public void openEditor(String fileName) { this.fileName = fileName; IFile testfile = project.getFile(fileName); // System.out.println(testfile.toString() + ": testfile.exists(): " + testfile.exists() + ", testfile.isAccessible(): " + testfile.isAccessible()); assertTrue("Test file doesn't exist: " + project.getName() + "/" + fileName, (testfile.exists() && testfile.isAccessible())); editorPart = WorkbenchUtils.openEditor(project.getName() + "/" + fileName); //$NON-NLS-1$ obtainEditor(editorPart); annotationModel = getAnnotationModel(); assertNotNull("Cannot find an Annotation Model for the Java Editor", annotationModel); // clean deffered events while (Display.getCurrent().readAndDispatch()) ; viewer = getTextViewer(); document = viewer.getDocument(); } public void closeEditor() { if (editorPart != null) { PlatformUI.getWorkbench().getActiveWorkbenchWindow() .getActivePage().closeEditor(editorPart, false); editorPart = null; textEditor = null; viewer = null; document = null; } } protected abstract void obtainEditor(IEditorPart editorPart); protected IAnnotationModel getAnnotationModel() { IDocumentProvider documentProvider = textEditor.getDocumentProvider(); return documentProvider == null ? null : documentProvider.getAnnotationModel(textEditor.getEditorInput()); } public IDocument getDocument() { return document; } public IFile getFile() { return file; } protected abstract ISourceViewer getTextViewer(); /** * The test procedure steps: * - Find EL by a given number * - Set up a good EL => see no annotations on that EL * - Set up a broken EL => see annotation appearance on that EL * - Set up a good EL again => see annotation to disappear on that EL * * @param goodEL * @param elToValidate * @param errorMessage * @param numberOfRegionToTest * @return boolean indicating that test was done for a region with a given number * @throws JavaModelException * @throws BadLocationException */ public boolean doAsYouTypeValidationTest(String goodEL, String elToValidate, String errorMessage, int numberOfRegionToTest) throws Exception { //============================ // The test procedure steps: // - Find EL by a given number //============================ String documentContent = document.get(); int count = -1; int start = 0; int end = 0; while (++count <= numberOfRegionToTest) { start = (documentContent == null ? -1 : documentContent .indexOf(EL2FIND_START, end)); if (start == -1 && count == numberOfRegionToTest) return false; assertFalse("No EL found in Java Strings: Starting '" + EL2FIND_START + "' characters are not found in document", (start == -1)); end = (documentContent == null ? -1 : documentContent.indexOf( EL2FIND_END, start)); if (end == -1 && count == numberOfRegionToTest) return false; assertFalse("EL is not closed in Java Strings: Ending '" + EL2FIND_START + "' characters are not found in document", (end == -1)); } if (count < numberOfRegionToTest) { // No more regions to test return false; } int length = end - start + EL2FIND_END.length(); //================================================== // - Set up a good EL => see no annotations on that EL //================================================== // System.out.println("Text to be replaced [0]: [" + document.get(start, length) + "]"); document.replace(start, length, goodEL); Annotation problemAnnotation = waitForAnnotation( start, end, null, MAX_SECONDS_TO_WAIT, false, false); assertNull("Problem Annotation found on a good EL!", problemAnnotation); length = goodEL.length(); //============================================================== // - Set up a broken EL => see annotation appearance on that EL //============================================================== // System.out.println("Text to be replaced [1]: [" + document.get(start, length) + "]"); document.replace(start, length, elToValidate); length = elToValidate.length(); end = start + elToValidate.length(); problemAnnotation = waitForAnnotation( start, end, errorMessage, MAX_SECONDS_TO_WAIT, false, true); assertNotNull("No Problem Annotation found!", problemAnnotation); String message = problemAnnotation.getText(); assertEquals( "Not expected error message found in ProblemAnnotation. Expected: [" + errorMessage + "], Found: [" + message + "]", errorMessage, message); //=================================================================== // - Set up a good EL again => see annotation to disappear on that EL //=================================================================== // System.out.println("Text to be replaced [2]: [" + document.get(start, length) + "]"); document.replace(start, length, goodEL); problemAnnotation = waitForAnnotation( start, end, null, MAX_SECONDS_TO_WAIT, false, false); assertNull("Problem Annotation has not disappeared!", problemAnnotation); return true; } /** * The test procedure steps: * - Find EL by a given number * - Set up a broken EL and save the document => see problem marker appearance on that EL * - Set up a another broken EL => see annotation appearance on that EL instead of a problem marker * (an old problem marker has to disappear) * - Set up a good EL again => see annotation to disappear on that EL * * @param goodEL * @param elToValidate * @param errorMessage * @param numberOfRegionToTest * @throws BadLocationException * @throws CoreException */ public boolean doAsYouTypeValidationMarkerAnnotationsRemovalTest(String goodEL, String elToValidate, String errorMessage, String anotherELToValidate, String anotherErrorMessage, int numberOfRegionToTest) throws BadLocationException, CoreException { // System.out.println("doAsYouTypeValidationMarkerAnnotationsRemovalTest(goodEL=" + goodEL + ", elToValidate=" + elToValidate + ", errorMessage=[" + errorMessage + // "],\n\tanotherELToValidate=" + anotherELToValidate+ ", anotherErrorMessage=[" + anotherErrorMessage + "], numberOfRegionToTest=" + numberOfRegionToTest + ")"); //============================ // The test procedure steps: // - Find EL by a given number //============================ String documentContent = document.get(); int count = -1; int start = 0; int end = 0; while (++count <= numberOfRegionToTest) { start = (documentContent == null ? -1 : documentContent .indexOf(EL2FIND_START, end)); if (start == -1 && count == numberOfRegionToTest) return false; assertFalse("No EL found in Java Strings: Starting '" + EL2FIND_START + "' characters are not found in document", (start == -1)); end = (documentContent == null ? -1 : documentContent.indexOf( EL2FIND_END, start)); if (end == -1 && count == numberOfRegionToTest) return false; assertFalse("EL is not closed in Java Strings: Ending '" + EL2FIND_START + "' characters are not found in document", (end == -1)); } if (count < numberOfRegionToTest) { // No more regions to test return false; } int length = end - start + EL2FIND_END.length(); //======================================================================================== // - Set up a broken EL and save the document => see problem marker appearance on that EL //======================================================================================== // System.out.println("Text to be replaced [0]: [" + document.get(start, length) + "]"); // document.replace(start, length, elToValidate); // document = viewer.getDocument(); // Probably we should find that EL again because the document may be re-formatted at save (?) // end = start + elToValidate.length(); // length = elToValidate.length(); // do check marker and marker annotation appeared here int line = document.getLineOfOffset(start); assertResourceMarkerIsCreated(file, errorMessage, line + 1); Annotation problemAnnotation = waitForAnnotation( start, end, errorMessage, MAX_SECONDS_TO_WAIT, true, true); assertNotNull("Problem Marker Annotation not found!", problemAnnotation); String message = problemAnnotation.getText(); assertEquals( "Not expected error message found in ProblemAnnotation. Expected: [" + errorMessage + "], Found: [" + message + "]", errorMessage, message); //================================================================================================= // - Set up a another broken EL => see annotation appearance on that EL instead of a problem marker // (an old problem marker has to disappear) //================================================================================================= // System.out.println("Text to be replaced [1]: [" + document.get(start, length) + "] by [" + anotherELToValidate + "]"); document.replace(start, length, anotherELToValidate); end = start + anotherELToValidate.length(); length = anotherELToValidate.length(); problemAnnotation = waitForAnnotation( start, end, anotherErrorMessage, MAX_SECONDS_TO_WAIT, false, true); assertNotNull("No Problem Annotation found for EL " + anotherELToValidate + " on region " + numberOfRegionToTest + "!", problemAnnotation); message = problemAnnotation.getText(); assertEquals( "Not expected error message found in ProblemAnnotation. Expected: [" + anotherErrorMessage + "], Found: [" + message + "]", anotherErrorMessage, message); // do check marker annotation has disappeared here problemAnnotation = waitForAnnotation( start, end, null, MAX_SECONDS_TO_WAIT, true, false); assertNull("Problem Marker Annotation has not disappeared!", problemAnnotation); //=================================================================== // - Set up a good EL again => see annotation to disappear on that EL //=================================================================== // System.out.println("Text to be replaced [2]: [" + document.get(start, length) + "] by [" + goodEL + "]"); document.replace(start, length, goodEL); problemAnnotation = waitForAnnotation( start, end, null, MAX_SECONDS_TO_WAIT, false, false); assertNull("Problem Annotation has not disappeared!", problemAnnotation); return true; } public Annotation waitForAnnotation(final int start, final int end, final String errorMessage, final int seconds, final boolean markerAnnotation, final boolean waitForAppearance) { final Annotation[] result = new Annotation[] { null }; final StringBuffer sb = new StringBuffer(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Display.getDefault().syncExec(new Runnable() { @SuppressWarnings("rawtypes") public void run() { int secondsLeft = seconds * 10; boolean isFirstPass = true; while (secondsLeft-- > 0) { if (!isFirstPass || waitForAppearance) { assertTrue("Running Platform UI is required!", PlatformUI.isWorkbenchRunning()); assertNotNull("Display is required!", Display.getCurrent()); Thread.yield(); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } JobUtils.delay(50); } else { secondsLeft++; // because the wait step was skipped } annotationModel = getAnnotationModel(); Iterator it = annotationModel.getAnnotationIterator(); boolean found = false; sb.replace(0, sb.length(), "Found annotations: [\r\n"); while (it.hasNext()) { Object o = it.next(); if (!(o instanceof Annotation)) continue; // System.out.println("A: " + (position == null ? null : position.toString()) + ", " + annotation.getClass().getName() + ", " + annotation.getType() + ", " + annotation.getText()); Annotation annotation = (Annotation) o; Position position = annotationModel.getPosition(annotation); try { sb.append("Text: ").append(annotation.getText()).append(", Position: ").append(position) .append(", Document Text: [").append(getDocument().get(position.getOffset(), (position.getOffset() + position.getLength() + 10 >= getDocument().getLength() ? getDocument().getLength() - position.getOffset() : position.getLength() + 10))) .append("]\r\n"); } catch (BadLocationException e) { e.printStackTrace(); } if (position == null) continue; if (position.getOffset() < start || position.getOffset() >= end) continue; if (position.getOffset() + position.getLength() > end) continue; if (!markerAnnotation && errorMessage != null && !errorMessage.equals(annotation.getText())) continue; // System.out.println("A: " + (position == null ? null : position.toString()) + ", " + annotation.getClass().getName() + ", " + annotation.getType() + ", " + annotation.getText()); found = markerAnnotation ? isMarkerAnnotationAcceptable(annotation) : isAnnotationAcceptable(annotation); if (found) { if (waitForAppearance) { // Return the annotation we've searched for result[0] = (Annotation)o; return; } else { // Continue to wait for annotation to disappear break; } } } sb.append("]"); // if waiting for an annotation to disappear then don't return at first pass if (!found && !waitForAppearance && !isFirstPass) { return; // Annotation not found or disappeared } isFirstPass = false; } } }); // System.out.println(result[0] == null ? "Not found":"found"); if(result[0]==null && errorMessage!=null) { try { System.out.println("Didn't find the following annotation: Text: " + errorMessage + "; Position:" + start + "(start), " + end + "(end)." +"Document Text: [" + getDocument().get(start, (end + 10 >= getDocument().getLength() ? getDocument().getLength() - start : end - start + 10))); } catch (BadLocationException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(sb); } return result[0]; } protected void waitForValidation(IProject project) throws CoreException{ project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); TestUtil._waitForValidation(project); } protected String modifyELInContent(StringBuilder content, String newEL) { if (content == null) return null; int start = 0; int end = 0; while (start != -1) { start = content.indexOf(EL2FIND_START, end); if (start == -1) break; end = content.indexOf(EL2FIND_END, start); if (end == -1) break; content.replace(start, end+1, newEL); } return content.toString(); } abstract protected boolean isAnnotationAcceptable(Annotation annotation); abstract protected boolean isMarkerAnnotationAcceptable(Annotation annotation); abstract protected void assertResourceMarkerIsCreated(IFile file, String errorMessage, int line) throws CoreException; }