aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java320
1 files changed, 320 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java
new file mode 100644
index 000000000..20aae846b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors;
+
+import static com.android.SdkConstants.FD_SOURCES;
+
+import com.android.ide.common.resources.ResourceFile;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.editors.Hyperlinks.ResourceLink;
+import com.android.ide.eclipse.adt.internal.editors.Hyperlinks.XmlResolver;
+import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.internal.ErrorEditorPart;
+import org.eclipse.ui.internal.browser.WebBrowserEditor;
+import org.eclipse.wst.sse.ui.StructuredTextEditor;
+import org.eclipse.wst.sse.ui.internal.StructuredTextViewer;
+import org.eclipse.wst.xml.ui.internal.tabletree.XMLMultiPageEditorPart;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+@SuppressWarnings({
+ "restriction", "javadoc"
+})
+public class HyperlinksTest extends AdtProjectTest {
+ @Override
+ protected boolean testCaseNeedsUniqueProject() {
+ return true;
+ }
+
+ public void testFqnRegexp() throws Exception {
+ assertTrue(Hyperlinks.isViewClassName("com.android.Foo"));
+ assertTrue(Hyperlinks.isViewClassName("com.android.pk_g.Foo_Bar1"));
+ assertTrue(Hyperlinks.isViewClassName("com.android.Foo$Inner"));
+
+ // Should we allow non-standard packages and class names?
+ // For now, we're allowing it -- see how this works out in practice.
+ //assertFalse(XmlHyperlinkResolver.isViewClassName("Foo.bar"));
+ assertTrue(Hyperlinks.isViewClassName("Foo.bar"));
+
+ assertFalse(Hyperlinks.isViewClassName("LinearLayout"));
+ assertFalse(Hyperlinks.isViewClassName("."));
+ assertFalse(Hyperlinks.isViewClassName(".F"));
+ assertFalse(Hyperlinks.isViewClassName("f."));
+ assertFalse(Hyperlinks.isViewClassName("Foo"));
+ assertFalse(Hyperlinks.isViewClassName("com.android.1Foo"));
+ assertFalse(Hyperlinks.isViewClassName("1com.Foo"));
+ }
+
+ public void testNavigate1() throws Exception {
+ // Check navigating to a local resource
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "android:text=\"@string/app^_name\"");
+ }
+
+ public void testNavigate2() throws Exception {
+ // Check navigating to a framework resource
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "marginLeft=\"@android:dimen/app_ico^n_size\"");
+ }
+
+ public void testNavigate3() throws Exception {
+ // Check navigating to a style
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "style=\"@android:style/Widget.B^utton\"");
+ }
+
+ public void testNavigate4() throws Exception {
+ // Check navigating to resource with many resolutions
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "android:text=\"@android:st^ring/ok\"");
+ }
+
+ public void testNavigate5() throws Exception {
+ // Check navigating to styles
+ checkXmlNavigation("navigationstyles.xml", "res/values/navigationstyles.xml",
+ "parent=\"android:Theme.Li^ght\">");
+ }
+
+ public void testNavigate6() throws Exception {
+ // Check navigating to a portion of a style (this should pick android:Theme, not
+ // android:Theme.Light
+ checkXmlNavigation("navigationstyles.xml", "res/values/navigationstyles.xml",
+ "parent=\"android:The^me.Light\">");
+ }
+
+ public void testNavigate7() throws Exception {
+ // Check navigating to a resource inside text content
+ checkXmlNavigation("navigationstyles.xml", "res/values/navigationstyles.xml",
+ "popupBackground\">@android:drawable/spinner_dr^opdown_background</item>");
+ }
+
+ public void testNavigate8() throws Exception {
+ // Check navigating to a resource inside text content where there is space around
+ // the URL
+ checkXmlNavigation("navigationstyles.xml", "res/values/navigationstyles.xml",
+ "colorBackground\"> @color/cust^om_theme_color </item>");
+ }
+
+ public void testNavigate9a() throws Exception {
+ // Check navigating to a an activity
+ checkXmlNavigation("manifest.xml", "AndroidManifest.xml",
+ "<activity android:name=\".Test^Activity\"");
+ }
+
+ /* Not yet implemented
+ public void testNavigate9b() throws Exception {
+ // Check navigating to a an activity - clicking on the activity element should
+ // work too
+ checkXmlNavigation("manifest.xml", "AndroidManifest.xml",
+ "<acti^vity android:name=\".TestActivity\"");
+ }
+ */
+
+ public void testNavigate10() throws Exception {
+ // Check navigating to a permission
+ checkXmlNavigation("manifest.xml", "AndroidManifest.xml",
+ "<uses-permission android:name=\"android.permission.AC^CESS_NETWORK_STATE\" />");
+ }
+
+ public void testNavigate11a() throws Exception {
+ // Check navigating to an intent
+ checkXmlNavigation("manifest.xml", "AndroidManifest.xml",
+ "<action android:name=\"android.intent.ac^tion.MAIN\" />");
+ }
+
+ public void testNavigate11g() throws Exception {
+ // Check navigating to an intent
+ checkXmlNavigation("manifest.xml", "AndroidManifest.xml",
+ "<category android:name=\"android.intent.category.LA^UNCHER\" />");
+ }
+
+ public void testNavigate12() throws Exception {
+ // Check navigating to a custom view class
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "<my.Cust^omView></my.CustomView>");
+ }
+
+ public void testNavigate13() throws Exception {
+ // Check jumping to classes pointed to by fragments
+
+ getTestDataFile(getProject(), "TestFragment.java.txt",
+ FD_SOURCES + "/" + TEST_PROJECT_PACKAGE.replace('.', '/') + "/TestFragment.java");
+ checkXmlNavigation("fragmentlayout.xml", "res/layout/fragmentlayout.xml",
+ "android:name=\"com.android.ecl^ipse.tests.TestFragment\"");
+ }
+
+ public void testNavigate14() throws Exception {
+ // Check jumping to classes pointed to by fragments
+
+ getTestDataFile(getProject(), "TestFragment.java.txt",
+ FD_SOURCES + "/" + TEST_PROJECT_PACKAGE.replace('.', '/') + "/TestFragment.java");
+ checkXmlNavigation("fragmentlayout.xml", "res/layout/fragmentlayout.xml",
+ "class=\"com.and^roid.eclipse.tests.TestFragment\"");
+ }
+
+ public void testNavigate15() throws Exception {
+ // Check navigating to a theme resource
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "?android:attr/alert^DialogStyle");
+ }
+
+ public void testNavigate16() throws Exception {
+ // Check navigating to a theme resource
+ checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml",
+ "?android:alert^DialogStyle");
+ }
+
+ // Left to test:
+ // onClick handling
+ // class attributes
+ // Test that the correct file is actually opened!
+
+ private void checkXmlNavigation(String basename, String targetPath,
+ String caretLocation) throws Exception {
+ IFile file = getTestDataFile(getProject(), basename, targetPath, true);
+
+ // Determine the offset
+ int offset = getCaretOffset(file, caretLocation);
+
+ // Open file
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ assertNotNull(page);
+ IEditorPart editor = IDE.openEditor(page, file);
+ assertTrue(editor.getClass().getName(), editor instanceof AndroidXmlEditor);
+ AndroidXmlEditor layoutEditor = (AndroidXmlEditor) editor;
+ ISourceViewer viewer = layoutEditor.getStructuredSourceViewer();
+
+ XmlResolver resolver = new Hyperlinks.XmlResolver();
+ IHyperlink[] links = resolver.detectHyperlinks(viewer, new Region(offset, 0), true);
+ assertNotNull(links);
+
+ StringBuilder sb = new StringBuilder(1000);
+ sb.append("Go To Declaration in " + basename + " for " + caretLocation + ":\n");
+ for (IHyperlink link : links) {
+ sb.append(link.getHyperlinkText());
+ sb.append(" : ");
+ sb.append(" [");
+ IRegion region = link.getHyperlinkRegion();
+ sb.append(viewer.getDocument().get(region.getOffset(), region.getLength()));
+ sb.append("]");
+ if (link instanceof Hyperlinks.ResourceLink) {
+ Hyperlinks.ResourceLink resourceLink = (ResourceLink) link;
+ sb.append("\n ");
+ ResourceFile resourceFile = resourceLink.getFile();
+ String desc = resourceFile.toString();
+ desc = desc.replace('\\', '/');
+ // For files in the SDK folder, strip out file prefix
+ int dataRes = desc.indexOf("data/res");
+ if (dataRes != -1) {
+ desc = desc.substring(dataRes);
+ }
+ desc = removeSessionData(desc);
+ sb.append(desc);
+ }
+ sb.append('\n');
+ }
+
+ // Open the first link
+ IHyperlink link = links[0];
+ link.open();
+ IEditorPart newEditor = AdtUtils.getActiveEditor();
+ // Ensure that this isn't an invalid file (e.g. opening the SDK platform files
+ // with incorrect content binding could cause this)
+ assertTrue(!(newEditor instanceof ErrorEditorPart));
+
+ IDocument document = null;
+ Point selection = null;
+
+ if (newEditor instanceof AndroidXmlEditor) {
+ AndroidXmlEditor xmlEditor = (AndroidXmlEditor) newEditor;
+ document = xmlEditor.getStructuredSourceViewer().getDocument();
+ selection = xmlEditor.getStructuredSourceViewer().getSelectedRange();
+ } else if (newEditor instanceof XMLMultiPageEditorPart) {
+ XMLMultiPageEditorPart xmlEditor = (XMLMultiPageEditorPart) newEditor;
+ Field field = xmlEditor.getClass().getDeclaredField("fTextEditor");
+ field.setAccessible(true);
+ StructuredTextEditor ste = (StructuredTextEditor) field.get(newEditor);
+ if (ste == null) {
+ Method method = xmlEditor.getClass().getMethod("getTextEditor", new Class[0]);
+ ste = (StructuredTextEditor) method.invoke(newEditor, new Object[0]);
+ }
+ StructuredTextViewer textViewer = ste.getTextViewer();
+ document = textViewer.getDocument();
+ selection = textViewer.getSelectedRange();
+ } else if (newEditor instanceof WebBrowserEditor) {
+ WebBrowserEditor browser = (WebBrowserEditor) newEditor;
+ Field field = browser.getClass().getDeclaredField("initialURL");
+ field.setAccessible(true);
+ String initialUrl = (String) field.get(newEditor);
+ int index = initialUrl.indexOf("reference");
+ if (index != -1) {
+ initialUrl = initialUrl.substring(index);
+ }
+ initialUrl = initialUrl.replace('\\', '/');
+ sb.append("\n\nAfter open, a browser is shown with this URL:\n");
+ sb.append(" ");
+ sb.append(initialUrl);
+ sb.append("\n");
+ } else if (newEditor instanceof JavaEditor) {
+ JavaEditor javaEditor = (JavaEditor) newEditor;
+ document = javaEditor.getDocumentProvider().getDocument(javaEditor.getEditorInput());
+ IRegion range = javaEditor.getHighlightRange();
+ selection = new Point(range.getOffset(), range.getLength());
+ } else {
+ fail("Unhandled editor type: " + newEditor.getClass().getName());
+ return;
+ }
+
+ if (document != null && selection != null) {
+ int lineStart = document.getLineInformationOfOffset(selection.x).getOffset();
+ IRegion lineEndInfo = document.getLineInformationOfOffset(selection.x + selection.y);
+ int lineEnd = lineEndInfo.getOffset() + lineEndInfo.getLength();
+ String text = document.get(lineStart, lineEnd - lineStart);
+ int selectionStart = selection.x - lineStart;
+ int selectionEnd = selectionStart + selection.y;
+ if (selectionEnd > selectionStart) {
+ // Selection range
+ text = text.substring(0, selectionStart) + "[^" +
+ text.substring(selectionStart, selectionEnd) + "]" +
+ text.substring(selectionEnd);
+ } else {
+ text = text.substring(0, selectionStart) + "^" +
+ text.substring(selectionStart);
+ }
+ text = removeSessionData(text);
+
+ sb.append("\n\nAfter open, the selected text is:\n");
+ sb.append(text);
+ sb.append("\n");
+ }
+
+ assertEqualsGolden(basename, sb.toString(), "txt");
+ }
+}