[250296] QVTO: test hyperlinks often fails
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AbstractTestQvtEditorSupport.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AbstractTestQvtEditorSupport.java
new file mode 100644
index 0000000..1290284
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AbstractTestQvtEditorSupport.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.m2m.internal.qvt.oml.builder.QvtBuilderConfig;
+import org.eclipse.m2m.internal.qvt.oml.common.MDAConstants;
+import org.eclipse.m2m.internal.qvt.oml.common.io.FileUtil;
+import org.eclipse.m2m.internal.qvt.oml.common.nature.TransformationNature;
+import org.eclipse.m2m.internal.qvt.oml.compiler.CompiledUnit;
+import org.eclipse.m2m.internal.qvt.oml.editor.ui.QvtDocumentProvider;
+import org.eclipse.m2m.internal.qvt.oml.editor.ui.QvtEditor;
+import org.eclipse.m2m.tests.qvt.oml.TestProject;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader;
+import org.eclipse.m2m.tests.qvt.oml.util.TestUtil;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.AnnotationData;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+public abstract class AbstractTestQvtEditorSupport extends TestCase {
+
+	protected String fTestFolder;
+	protected QvtEditor fEditor;
+	protected IContainer fSrcContainer;
+	protected TestProject fTestProject;
+	protected Map<IFile, List<AnnotationData>> fAnnotationMap;
+
+	public AbstractTestQvtEditorSupport(String name) {
+		super(name);
+		fTestFolder = name;
+	}
+	
+	protected static String getSourceContents(ITextEditor editor) {
+		return editor.getDocumentProvider().getDocument(editor.getEditorInput()).get();
+	}
+	
+	protected List<AnnotationData> readSourceAnnotations(ITextEditor editor) {
+		assertTrue("QVT Editor instance expected", editor instanceof QvtEditor); //$NON-NLS-1$
+		QvtEditor qvtEditor = (QvtEditor) editor;
+		
+		IFile file = getSourceFile(qvtEditor);
+		return fAnnotationMap.get(file);
+		
+		//return new SourceAnnotationReader(qvtEditor.getEditorSourceViewer().getDocument().get()).getAnnotations();		
+	}
+	
+	protected static QvtDocumentProvider getQVTDocumentProvider(ITextEditor editor) {
+		assertTrue("QVT Editor instance expected", editor instanceof QvtEditor); //$NON-NLS-1$
+		assertTrue("Requires QVT document provider", editor.getDocumentProvider() instanceof QvtDocumentProvider); //$NON-NLS-1$
+		return (QvtDocumentProvider) editor.getDocumentProvider();
+	}
+	
+	protected static QvtEditor openInEditor(IFile transformationFile) {
+		QvtEditor editor = null;
+		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		try {
+			ITextEditor textEditor = (QvtEditor) IDE.openEditor(page, transformationFile);
+			assertTrue("QVT Editor instance expected", textEditor instanceof QvtEditor); //$NON-NLS-1$
+			editor = (QvtEditor) textEditor;
+			
+			final int WAIT_FOR_RECONCILE = 15000;
+			editor.forceReconciling();
+			CompiledUnit compiledModule = editor.getValidCompiledModule(WAIT_FOR_RECONCILE);
+			
+			assertNotNull("Failed to aquire AST model in QVT Editor", compiledModule); //$NON-NLS-1$
+			
+		} catch (PartInitException e) {
+			fail("Failed to open QVTEditor. " + e); //$NON-NLS-1$
+		}
+		return editor;
+	}
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+	
+		Set<String> enabledActivityIds = PlatformUI.getWorkbench().getActivitySupport().getActivityManager().getEnabledActivityIds();
+		Set<String> copyEnabledActivityIds = new HashSet<String>(enabledActivityIds);
+		copyEnabledActivityIds.add("com.borland.qvto");  //$NON-NLS-1$
+		PlatformUI.getWorkbench().getActivitySupport().setEnabledActivityIds(copyEnabledActivityIds);
+		
+		initializeProject();
+		IFile sourceFile = (IFile)fSrcContainer.findMember(fTestFolder + MDAConstants.QVTO_FILE_EXTENSION_WITH_DOT);
+		assertNotNull(sourceFile);
+		fEditor = openInEditor(sourceFile);
+		assertNotNull(fEditor);	
+	}	
+	
+	protected void initializeProject() throws Exception {
+		fTestProject = new TestProject("Editor", new String[] {TransformationNature.ID}); //$NON-NLS-1$
+	
+		File srcFolder = TestUtil.getPluginRelativeFile(TestUtil.BUNDLE, "parserTestData/editor/" + fTestFolder); //$NON-NLS-1$
+	    fSrcContainer = QvtBuilderConfig.getConfig(fTestProject.getProject()).getSourceContainer();
+	    File destFolder = fSrcContainer.getLocation().toFile();
+	    FileUtil.copyFolder(srcFolder, destFolder);
+	    
+	    fTestProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
+	    processSourceAnnotations(destFolder);
+	}
+	
+	protected IEditorPart getActiveEditor() {
+		IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+		return page.getActiveEditor();
+	}
+	
+	private void processSourceAnnotations(File dest) throws Exception {
+		fAnnotationMap = new HashMap<IFile, List<AnnotationData>>();
+		
+		IContainer[] containers = ResourcesPlugin.getWorkspace().getRoot().findContainersForLocationURI(dest.toURI());
+		IContainer c = containers[0];
+		IResource[] members = c.members();
+		for (IResource resource : members) {
+			if(resource.getType() == IResource.FILE && 
+				MDAConstants.QVTO_FILE_EXTENSION.equals(resource.getFileExtension())) {
+				IFile file = (IFile) resource;
+				String contents = FileUtil.getStreamContents(file.getContents(), file.getCharset());
+				
+				SourceAnnotationReader annotationReader = new SourceAnnotationReader(contents);				
+
+				String newContents  = annotationReader.getSource();				
+				InputStream is = new ByteArrayInputStream(newContents.getBytes(file.getCharset()));
+				file.setContents(is, true, false, null);
+				
+				fAnnotationMap.put(file, annotationReader.getAnnotations());
+			}
+		}
+	}
+
+	static IFile getSourceFile(QvtEditor editor) {
+		FileEditorInput editorInput = (FileEditorInput)editor.getEditorInput();
+		return editorInput.getFile();
+	}
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AllEditorTests.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AllEditorTests.java
new file mode 100644
index 0000000..ead92b1
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/AllEditorTests.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllEditorTests {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite("Test for org.eclipse.m2m.tests.qvt.oml.ui.editor"); //$NON-NLS-1$
+		//$JUnit-BEGIN$
+		suite.addTestSuite(TestQvtProblemAnnotations.class);
+		suite.addTestSuite(TestSourceAnnotationReader.class);	
+		suite.addTestSuite(TestEditorHyperLinks.class);
+		//$JUnit-END$
+		return suite;
+	}
+
+}
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/HyperLinkHelper.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/HyperLinkHelper.java
new file mode 100644
index 0000000..fd597c0
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/HyperLinkHelper.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.AnnotationData;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.RegionInfo;
+
+class HyperLinkHelper {
+
+	static class SourceHyperLink {
+		final AnnotationData link;
+		final IRegion targeRegion;
+		final String targetModule;
+		final URI targetElemenUri;
+		
+		SourceHyperLink(AnnotationData link, final RegionInfo target) {
+			this.link = link;
+			this.targeRegion = new IRegion() {
+
+				public int getLength() {
+					return target.getLength();
+				}
+
+				public int getOffset() {
+					return target.getOffset();
+				}
+				
+			};
+			this.targetModule = null;
+			this.targetElemenUri = null;
+			
+		}
+
+		SourceHyperLink(AnnotationData link, IRegion target) {
+			this.link = link;
+			this.targeRegion = target;
+			this.targetModule = null;
+			this.targetElemenUri = null;
+			
+		}
+
+		SourceHyperLink(AnnotationData link, URI targetElemenUri) {
+			this.link = link;
+			this.targetElemenUri = targetElemenUri;
+			this.targetModule = null;
+			this.targeRegion = null;
+		}
+		
+		SourceHyperLink(AnnotationData link, String sourceModule) {
+			this.link = link;
+			this.targetModule = sourceModule;
+			this.targetElemenUri = null;
+			this.targeRegion = null;
+		}
+		
+		@Override
+		public String toString() {
+			return link.toString();
+		}
+	}
+	
+	public static final String HYPERLINK_TAG = "link"; //$NON-NLS-1$
+	public static final String HYPERLINK_REF_ATTR = "ref";	//$NON-NLS-1$
+	public static final String HYPERLINK_MODULE_ATTR = "module"; //$NON-NLS-1$	
+	public static final String HYPERLINK_ELEMENT_URI_ATTR = "elementUri"; //$NON-NLS-1$		
+	public static final String REGION_TAG = "region"; //$NON-NLS-1$
+	public static final String REGION_ID_ATTR = "id"; //$NON-NLS-1$
+
+	
+	private List<SourceHyperLink> fHLinks = new ArrayList<SourceHyperLink>();
+	private Map<String, AnnotationData> fTargetRegions = new HashMap<String, AnnotationData>();
+	
+	
+	HyperLinkHelper(List<AnnotationData> annotations) {
+		fTargetRegions = new HashMap<String, AnnotationData>();
+		List<AnnotationData> links = new ArrayList<AnnotationData>();
+		
+		for (AnnotationData a : annotations) {
+			if(HYPERLINK_TAG.equals(a.getName())) {
+				links.add(a);
+			} 
+			else if(REGION_TAG.equals(a.getName())) {
+				String id = a.getAttrValue(REGION_ID_ATTR);
+				if(id != null) {
+					if(fTargetRegions.put(id, a) != null) {
+						throw new RuntimeException("Region already defined. " + a); //$NON-NLS-1$
+					}
+				}
+			} 
+			else {
+				throw new RuntimeException("Uknown test source annotation type"); //$NON-NLS-1$
+			}
+		}
+		
+		for (AnnotationData nextLink : links) {
+			String refId = nextLink.getAttrValue(HYPERLINK_REF_ATTR);
+			if(refId != null) {
+				AnnotationData targetReg = fTargetRegions.get(refId);
+				if(targetReg == null && nextLink.getAttrValue(HYPERLINK_MODULE_ATTR) == null) {
+					throw new RuntimeException("No target region for link annotation found:" + nextLink); //$NON-NLS-1$
+				}
+
+				if(nextLink.getAttrValue(HYPERLINK_MODULE_ATTR) != null) {				
+					fHLinks.add(new SourceHyperLink(nextLink, nextLink.getAttrValue(HYPERLINK_MODULE_ATTR)));
+				} else {
+					fHLinks.add(new SourceHyperLink(nextLink, targetReg.getAnnotatedRegion()));
+				}
+			} 
+			else if(nextLink.getAttrValue(HYPERLINK_ELEMENT_URI_ATTR) != null) {
+				URI uri = URI.createURI(nextLink.getAttrValue(HYPERLINK_ELEMENT_URI_ATTR));
+				fHLinks.add(new SourceHyperLink(nextLink, uri));
+			}
+			else {
+				throw new RuntimeException("Hyperlink annotation must specify 'ref' or 'elementUri' attribute"); //$NON-NLS-1$
+			}			
+		}
+	}
+	
+	public List<SourceHyperLink> getHyperLinks() {
+		return fHLinks;
+	}	
+	
+	public AnnotationData getTargetRegion(String id) {
+		return fTargetRegions.get(id);
+	}
+}
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestEditorHyperLinks.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestEditorHyperLinks.java
new file mode 100644
index 0000000..a745d77
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestEditorHyperLinks.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EModelElement;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextHoverExtension2;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.m2m.internal.qvt.oml.editor.ui.QvtEditor;
+import org.eclipse.m2m.internal.qvt.oml.editor.ui.hyperlinks.QvtHyperlinkDetector;
+import org.eclipse.m2m.internal.tests.qvt.oml.ui.editor.HyperLinkHelper.SourceHyperLink;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.AnnotationData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.PlatformUI;
+
+
+public class TestEditorHyperLinks extends AbstractTestQvtEditorSupport {
+
+	private static final int TEST_LINK_COUNT = 38;
+	
+	// TODO - Should not be copied here but exposed by Metamodel Browser
+	private static final String METAMODEL_BROWSER_VIEW_ID = "org.eclipse.m2m.internal.qvt.oml.common.views.MetamodelBrowserView"; //$NON-NLS-1$
+
+	public TestEditorHyperLinks(String test) {
+		super(test);
+	}
+	
+	public void testhyperlinks() throws Exception {
+		doTest(TEST_LINK_COUNT);
+	}
+	
+	private void doRunTestChecks(int[] testResult) {
+		final List<AnnotationData> sourceAnnotations = readSourceAnnotations(fEditor);		
+		HyperLinkHelper hyperLinkBindings = new HyperLinkHelper(sourceAnnotations);
+		for (SourceHyperLink sourceHLink : hyperLinkBindings.getHyperLinks()) {
+			IRegion pointerReg = new Region(sourceHLink.link.getAnnotatedRegion().getOffset(), 0);
+			
+			IHyperlink[] hyperlinks = new QvtHyperlinkDetector(fEditor).detectHyperlinks(fEditor.getEditorSourceViewer(), pointerReg, false);
+			assertNotNull(message("No hyperlink detected for", sourceHLink), hyperlinks); //$NON-NLS-1$
+			assertEquals(1, hyperlinks.length);
+			
+			IHyperlink hlink = hyperlinks[0];
+			IRegion hlinkRegion = new Region(sourceHLink.link.getAnnotatedRegion().getOffset(), sourceHLink.link.getAnnotatedRegion().getLength());					
+			assertEquals(sourceHLink.toString(), 
+					hlink.getHyperlinkRegion().getOffset(), hlinkRegion.getOffset());
+			assertEquals(sourceHLink.toString(), 
+					hlink.getHyperlinkRegion().getLength(), hlinkRegion.getLength());					
+			
+			ITextHover hover = fEditor.getQvtConfiguration().getTextHover(fEditor.getEditorSourceViewer(), null);
+			assertNotNull("Text hover must be available", hover); //$NON-NLS-1$
+			String hoverText = (String)((ITextHoverExtension2)hover).getHoverInfo2(fEditor.getEditorSourceViewer(), pointerReg);
+			assertTrue(message("No hover for hyperlink", sourceHLink), //$NON-NLS-1$ 
+					hoverText != null && hoverText.trim().length() > 0);
+			
+			// Navigate to hyper-link destination			
+			hlink.open();
+			
+			if(sourceHLink.targetModule != null) {
+				QvtEditor mainEditor = fEditor;
+				IFile mainSourceFile = getSourceFile(mainEditor);
+				IFile targetFile = (IFile)mainSourceFile.getParent().findMember(sourceHLink.targetModule + ".qvto"); //$NON-NLS-1$
+				QvtEditor expectedActiveEditor = openInEditor(targetFile);							
+				assertSame(expectedActiveEditor, getActiveEditor());
+				assertNotSame(expectedActiveEditor, mainEditor);
+
+				List<AnnotationData> targetAnnotations = readSourceAnnotations(expectedActiveEditor);
+				AnnotationData target = new HyperLinkHelper(targetAnnotations).getTargetRegion(sourceHLink.link.getAttrValue(HyperLinkHelper.HYPERLINK_REF_ATTR));
+				
+				Point targetPost = expectedActiveEditor.getEditorSourceViewer().getSelectedRange();
+				int targetOffset = target.getAnnotatedRegion().getOffset();
+				int targetRangeLen = target.getAnnotatedRegion().getLength();
+				assertEquals(sourceHLink.toString(), targetPost.x, targetOffset);
+				assertEquals(sourceHLink.toString(), targetPost.y, targetRangeLen);							
+				
+				expectedActiveEditor.close(false);
+				testResult[0]++;						
+				
+			} else if(sourceHLink.targeRegion != null) {						
+				Point targetPost = fEditor.getEditorSourceViewer().getSelectedRange();					
+				int targetOffset = sourceHLink.targeRegion.getOffset();
+				int targetRangeLen = sourceHLink.targeRegion.getLength();
+				assertEquals(message("Link failed:", sourceHLink), targetPost.x, targetOffset);
+				assertEquals(sourceHLink.toString(), targetPost.y, targetRangeLen);							
+				
+				testResult[0]++;
+			} else if(sourceHLink.targetElemenUri != null) {
+				EModelElement targetElement = findResolvedTargetMetamodelElement();
+				assertNotNull(message("Navigated element must be selected", sourceHLink), //$NON-NLS-1$ 
+						targetElement);
+				URI resolvedUri = EcoreUtil.getURI(targetElement);
+				assertNotNull(message("Element of expected URI must be found", sourceHLink), //$NON-NLS-1$
+						sourceHLink.targetElemenUri.equals(resolvedUri)); 
+				
+				testResult[0]++;
+			}
+		}
+	}	
+	
+	private void doTest(int expectedHyperLinkCount) throws AssertionFailedError {		
+		final int[] testResult = new int[] { 0 };
+		final Throwable[] testError = new Throwable[] { null };
+		
+		Display.getCurrent().syncExec(new Runnable() {			
+			public void run() {
+				try {
+					doRunTestChecks(testResult);
+				} catch (Throwable e) {
+					testError[0] = e;
+				}
+			}
+		});			
+		
+		if(testError[0] != null) {
+			Throwable t = testError[0];
+			if(t instanceof AssertionFailedError) {
+				throw (AssertionFailedError)t;
+			} 
+			
+			t.printStackTrace();			
+			fail(t.toString());			
+		}
+		
+		assertTrue("Not all hyper links have been resolved succesfully", testResult[0] >= expectedHyperLinkCount); //$NON-NLS-1$
+	}
+	
+	
+	private EModelElement findResolvedTargetMetamodelElement() {
+		IViewPart view = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(METAMODEL_BROWSER_VIEW_ID);
+		assertNotNull(view);
+		assertFalse(view.getViewSite().getSelectionProvider().getSelection().isEmpty());
+
+		ISelection sel = view.getViewSite().getSelectionProvider().getSelection();
+		if(sel instanceof IStructuredSelection) {			
+			IStructuredSelection structSel = (IStructuredSelection) sel;
+			Object elementHolder = structSel.getFirstElement();
+			assertTrue("Must be IAdaptable element", elementHolder instanceof IAdaptable); //$NON-NLS-1$
+			IAdaptable adaptable = (IAdaptable)elementHolder;
+			return (EModelElement)adaptable.getAdapter(EModelElement.class);
+		}
+		
+		return null;
+	}
+			
+	private String message(String message, SourceHyperLink link) {
+		return message + " - " + link.toString(); //$NON-NLS-1$
+	}
+}
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestQvtProblemAnnotations.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestQvtProblemAnnotations.java
new file mode 100644
index 0000000..c6c96d8
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestQvtProblemAnnotations.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.m2m.internal.qvt.oml.QvtMessage;
+import org.eclipse.m2m.internal.qvt.oml.editor.ui.IQvtAnnotationTypes;
+import org.eclipse.m2m.tests.qvt.oml.util.ProblemSourceAnnotationHelper;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.AnnotationData;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.RegionInfo;
+
+public class TestQvtProblemAnnotations extends AbstractTestQvtEditorSupport {
+
+	private List<QvtMessage> fProblems;
+	
+	public TestQvtProblemAnnotations(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();		
+		fProblems = getQVTDocumentProvider(fEditor).getCompiledModule().getProblems();
+	}
+		
+	public void testProblemAnnotations() throws Exception {		
+		List<AnnotationData> sourceAnnotations = readSourceAnnotations(fEditor);
+		assertFalse(sourceAnnotations.isEmpty());
+		
+		ProblemSourceAnnotationHelper problemHelper = new ProblemSourceAnnotationHelper(sourceAnnotations);
+		IAnnotationHover hover = fEditor.getQvtConfiguration().getAnnotationHover(fEditor.getEditorSourceViewer());
+
+		
+		for (QvtMessage problemMessage : fProblems) {
+			AnnotationData expectedAnnotation = problemHelper.findAnnotationByPosition(problemMessage);
+			assertNotNull(expectedAnnotation);
+			
+			Annotation foundEditorAnnotation = findAnnotation(expectedAnnotation.getAnnotatedRegion());
+			assertNotNull(foundEditorAnnotation);			
+
+			assertTrue(ProblemSourceAnnotationHelper.isTheSameSeverity(expectedAnnotation, problemMessage));
+			if(ProblemSourceAnnotationHelper.isError(expectedAnnotation)) {
+				assertEquals(IQvtAnnotationTypes.ERROR, foundEditorAnnotation.getType());
+			} else if(ProblemSourceAnnotationHelper.isWarning(expectedAnnotation)) {
+				assertEquals(IQvtAnnotationTypes.WARNING, foundEditorAnnotation.getType());
+			} else {
+				fail("Unexpected problem severity"); //$NON-NLS-1$
+			}
+			
+			assertTrue("Problem message must be used", problemMessage.getMessage().contains(foundEditorAnnotation.getText())); //$NON-NLS-1$
+			
+			int line = fEditor.getDocumentProvider().getDocument(fEditor.getEditorInput())
+				.getLineOfOffset(problemMessage.getOffset());
+			String hoverText = hover.getHoverInfo(fEditor.getEditorSourceViewer(), line);
+			assertTrue("Hover text should include problem message", //$NON-NLS-1$
+					hoverText != null && hoverText.contains(problemMessage.getMessage()));			
+		}		
+	}
+	
+	private Annotation findAnnotation(RegionInfo region) {
+		Iterator<?> it = fEditor.getAnnotationModel().getAnnotationIterator();
+		while(it.hasNext()) {
+			Annotation nextAnnotation = (Annotation) it.next();
+			Position pos = fEditor.getAnnotationModel().getPosition(nextAnnotation); 
+			if(region.getOffset() == pos.offset && region.getLength() == pos.length) {
+				return nextAnnotation;
+			}
+		}
+		
+		return null;
+	}
+}
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestSourceAnnotationReader.java b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestSourceAnnotationReader.java
new file mode 100644
index 0000000..8f304df
--- /dev/null
+++ b/tests/org.eclipse.m2m.tests.qvt.oml.ui/src/org/eclipse/m2m/internal/tests/qvt/oml/ui/editor/TestSourceAnnotationReader.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Borland Software Corporation
+ * 
+ * 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:
+ *     Borland Software Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.internal.tests.qvt.oml.ui.editor;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.AnnotationData;
+import org.eclipse.m2m.tests.qvt.oml.util.SourceAnnotationReader.RegionInfo;
+
+public class TestSourceAnnotationReader extends TestCase {
+
+	public TestSourceAnnotationReader(String name) {
+		super(name);
+	}
+	
+	public void testAnnotations() throws Exception {
+		String source = "Aa/*<pos id='idval'/>*/Bb Cc/*<w code='5' refid='idval'>*/{contents}/*</w>*/Dd"; //$NON-NLS-1$
+		SourceAnnotationReader reader = new SourceAnnotationReader(source);
+		List<AnnotationData> annotations = reader.getAnnotations();
+		
+		assertEquals(2, annotations.size());
+
+		AnnotationData a1 = annotations.get(0);
+		assertEquals("pos", a1.getName()); //$NON-NLS-1$
+		assertEquals("idval", a1.getAttrValue("id")); //$NON-NLS-1$ //$NON-NLS-2$
+
+		assertEquals(reader.getSource().indexOf("Bb"), a1.getAnnotatedRegion().getOffset());
+		assertEquals(a1.getAnnotatedRegion().getLength(), 0);		
+		
+		AnnotationData a2 = annotations.get(1);	
+		assertEquals("w", a2.getName()); //$NON-NLS-1$
+		assertEquals("5", a2.getAttrValue("code")); //$NON-NLS-1$ //$NON-NLS-2$
+		assertEquals("idval", a2.getAttrValue("refid")); //$NON-NLS-1$ //$NON-NLS-2$		
+		assertEquals("{contents}", getRegionContents(reader.getSource(), a2.getAnnotatedRegion())); //$NON-NLS-1$
+		assertEquals("{contents}".length(), a2.getAnnotatedRegion().getLength()); //$NON-NLS-1$		
+		assertEquals('{', reader.getSource().charAt(a2.getAnnotatedRegion().getOffset()));		
+	}
+	
+	private static String getRegionContents(String source, RegionInfo region) {
+		return source.substring(region.getOffset(), region.getOffset() + region.getLength());
+	}
+}