| /* |
| * Copyright (C) 2011 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.build; |
| |
| import static com.android.SdkConstants.FD_RES; |
| import static com.android.SdkConstants.FD_RES_COLOR; |
| import static com.android.SdkConstants.FD_RES_LAYOUT; |
| |
| import com.android.ide.eclipse.adt.AdtConstants; |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.ide.eclipse.adt.AdtUtils; |
| import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; |
| import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IMarkerResolution; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.ide.IDE; |
| import org.eclipse.ui.part.FileEditorInput; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class AaptQuickFixTest extends AdtProjectTest { |
| @Override |
| protected boolean testCaseNeedsUniqueProject() { |
| // Make a separate test project for this test such that we don't pollute code assist |
| // tests with our new resources |
| return true; |
| } |
| |
| public void testQuickFix1() throws Exception { |
| // Test adding a value into an existing file (res/values/strings.xml) |
| checkResourceFix("quickfix1.xml", "android:text=\"@string/firs^tstring\"", |
| "res/values/strings.xml"); |
| } |
| |
| public void testQuickFix2() throws Exception { |
| // Test adding a value into a new file (res/values/dimens.xml, will be created) |
| checkResourceFix("quickfix1.xml", "android:layout_width=\"@dimen/^testdimen\"", |
| "res/values/dimens.xml"); |
| } |
| |
| public void testQuickFix3() throws Exception { |
| // Test adding a file based resource (uses new file wizard machinery) |
| checkResourceFix("quickfix1.xml", "layout=\"@layout/^testlayout\"", |
| "res/layout/testlayout.xml"); |
| } |
| |
| public void testQuickFix4() throws Exception { |
| // Test adding a value into a new file (res/values/dimens.xml, will be created) |
| checkNamespaceFix("quickfix2.xml", "<c^olor"); |
| } |
| |
| private void checkResourceFix(String name, String caretLocation, String expectedNewPath) |
| throws Exception { |
| IProject project = getProject(); |
| IFile file = getTestDataFile(project, name, FD_RES + "/" + FD_RES_LAYOUT + "/" + name); |
| |
| // Determine the offset |
| final int offset = getCaretOffset(file, caretLocation); |
| |
| |
| String osRoot = project.getLocation().toOSString(); |
| List<String> errors = new ArrayList<String>(); |
| String fileRelativePath = file.getProjectRelativePath().toPortableString(); |
| String filePath = osRoot + File.separator + fileRelativePath; |
| // Run AaptParser such that markers are added... |
| // When debugging these tests, the project gets a chance to build itself so |
| // the real aapt errors are there. But when the test is run directly, aapt has |
| // not yet run. I tried waiting for the build (using the code in SampleProjectTest) |
| // but this had various adverse effects (exception popups from the Eclipse debugger |
| // etc) so instead this test just hardcodes the aapt errors that should be |
| // observed on quickfix1.xml. |
| assertEquals("Unit test is hardcoded to errors for quickfix1.xml", "quickfix1.xml", name); |
| errors.add(filePath + ":7: error: Error: No resource found that matches the given name" |
| + " (at 'text' with value '@string/firststring')."); |
| errors.add(filePath + ":7: error: Error: No resource found that matches the given name" |
| + " (at 'layout_width' with value '@dimen/testdimen')."); |
| errors.add(filePath + ":13: error: Error: No resource found that matches the given name" |
| + " (at 'layout' with value '@layout/testlayout')."); |
| AaptParser.parseOutput(errors, project); |
| |
| AaptQuickFix aaptQuickFix = new AaptQuickFix(); |
| |
| // Open file |
| IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); |
| assertNotNull(page); |
| IEditorPart editor = IDE.openEditor(page, file); |
| assertTrue(editor instanceof AndroidXmlEditor); |
| AndroidXmlEditor layoutEditor = (AndroidXmlEditor) editor; |
| final ISourceViewer viewer = layoutEditor.getStructuredSourceViewer(); |
| |
| // Test marker resolution. |
| IMarker[] markers = file.findMarkers(AdtConstants.MARKER_AAPT_COMPILE, true, |
| IResource.DEPTH_ZERO); |
| for (IMarker marker : markers) { |
| int start = marker.getAttribute(IMarker.CHAR_START, 0); |
| int end = marker.getAttribute(IMarker.CHAR_END, 0); |
| if (offset >= start && offset <= end) { |
| // Found the target marker. Now check the marker resolution of it. |
| assertTrue(aaptQuickFix.hasResolutions(marker)); |
| IMarkerResolution[] resolutions = aaptQuickFix.getResolutions(marker); |
| assertNotNull(resolutions); |
| assertEquals(1, resolutions.length); |
| IMarkerResolution resolution = resolutions[0]; |
| assertNotNull(resolution); |
| assertTrue(resolution.getLabel().contains("Create resource")); |
| |
| // Not running marker yet -- if we create the files here they already |
| // exist when the quick assist code runs. (The quick fix and the quick assist |
| // mostly share code for the implementation anyway.) |
| //resolution.run(marker); |
| break; |
| } |
| } |
| |
| // Next test quick assist. |
| |
| IQuickAssistInvocationContext invocationContext = new IQuickAssistInvocationContext() { |
| @Override |
| public int getLength() { |
| return 0; |
| } |
| |
| @Override |
| public int getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public ISourceViewer getSourceViewer() { |
| return viewer; |
| } |
| }; |
| ICompletionProposal[] proposals = aaptQuickFix |
| .computeQuickAssistProposals(invocationContext); |
| assertNotNull(proposals); |
| assertTrue(proposals.length == 1); |
| ICompletionProposal proposal = proposals[0]; |
| |
| assertNotNull(proposal.getAdditionalProposalInfo()); |
| assertNotNull(proposal.getImage()); |
| assertTrue(proposal.getDisplayString().contains("Create resource")); |
| |
| IDocument document = new Document(); |
| String fileContent = AdtPlugin.readFile(file); |
| document.set(fileContent); |
| |
| // Apply quick fix |
| proposal.apply(document); |
| |
| IPath path = new Path(expectedNewPath); |
| IFile newFile = project.getFile(path); |
| assertNotNull(path.toPortableString(), newFile); |
| |
| // Ensure that the newly created file was opened |
| IEditorPart currentFile = AdtUtils.getActiveEditor(); |
| assertEquals(newFile.getProjectRelativePath(), |
| ((FileEditorInput) currentFile.getEditorInput()).getFile().getProjectRelativePath()); |
| |
| // Look up caret offset |
| assertTrue(currentFile != null ? currentFile.getClass().getName() : "null", |
| currentFile instanceof AndroidXmlEditor); |
| AndroidXmlEditor newEditor = (AndroidXmlEditor) currentFile; |
| ISourceViewer newViewer = newEditor.getStructuredSourceViewer(); |
| Point selectedRange = newViewer.getSelectedRange(); |
| |
| String newFileContents = AdtPlugin.readFile(newFile); |
| |
| // Insert selection markers -- [ ] for the selection range, ^ for the caret |
| String newFileWithCaret = addSelection(newFileContents, selectedRange); |
| newFileWithCaret = removeSessionData(newFileWithCaret); |
| |
| assertEqualsGolden(name, newFileWithCaret); |
| } |
| |
| private void checkNamespaceFix(String name, String caretLocation) |
| throws Exception { |
| IProject project = getProject(); |
| IFile file = getTestDataFile(project, name, FD_RES + "/" + FD_RES_COLOR + "/" + name); |
| |
| // Determine the offset |
| final int offset = getCaretOffset(file, caretLocation); |
| |
| String osRoot = project.getLocation().toOSString(); |
| List<String> errors = new ArrayList<String>(); |
| String fileRelativePath = file.getProjectRelativePath().toPortableString(); |
| String filePath = osRoot + File.separator + fileRelativePath; |
| assertEquals("Unit test is hardcoded to errors for quickfix2.xml", "quickfix2.xml", name); |
| errors.add(filePath + ":5: error: Error parsing XML: unbound prefix"); |
| AaptParser.parseOutput(errors, project); |
| |
| AaptQuickFix aaptQuickFix = new AaptQuickFix(); |
| |
| // Open file |
| IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); |
| assertNotNull(page); |
| IEditorPart editor = IDE.openEditor(page, file); |
| assertTrue(editor instanceof AndroidXmlEditor); |
| AndroidXmlEditor layoutEditor = (AndroidXmlEditor) editor; |
| final ISourceViewer viewer = layoutEditor.getStructuredSourceViewer(); |
| |
| // Test marker resolution. |
| IMarker[] markers = file.findMarkers(AdtConstants.MARKER_AAPT_COMPILE, true, |
| IResource.DEPTH_ZERO); |
| assertEquals(1, markers.length); |
| IMarker marker = markers[0]; |
| // Found the target marker. Now check the marker resolution of it. |
| assertTrue(aaptQuickFix.hasResolutions(marker)); |
| IMarkerResolution[] resolutions = aaptQuickFix.getResolutions(marker); |
| assertNotNull(resolutions); |
| assertEquals(1, resolutions.length); |
| IMarkerResolution resolution = resolutions[0]; |
| assertNotNull(resolution); |
| assertTrue(resolution.getLabel().contains("Insert namespace")); |
| |
| // Next test quick assist. |
| |
| IQuickAssistInvocationContext invocationContext = new IQuickAssistInvocationContext() { |
| @Override |
| public int getLength() { |
| return 0; |
| } |
| |
| @Override |
| public int getOffset() { |
| return offset; |
| } |
| |
| @Override |
| public ISourceViewer getSourceViewer() { |
| return viewer; |
| } |
| }; |
| ICompletionProposal[] proposals = aaptQuickFix |
| .computeQuickAssistProposals(invocationContext); |
| assertNotNull(proposals); |
| assertTrue(proposals.length == 1); |
| ICompletionProposal proposal = proposals[0]; |
| |
| assertNotNull(proposal.getAdditionalProposalInfo()); |
| assertNotNull(proposal.getImage()); |
| assertTrue(proposal.getDisplayString().contains("Insert namespace")); |
| |
| // Open the file to ensure we can get an XML model with getExistingModelForEdit: |
| AdtPlugin.openFile(file, null); |
| IEditorPart newEditor = AdtUtils.getActiveEditor(); |
| assertTrue(newEditor instanceof AndroidXmlEditor); |
| |
| AndroidXmlEditor xmlEditor = (AndroidXmlEditor) newEditor; |
| IDocument document = xmlEditor.getStructuredSourceViewer().getDocument(); |
| |
| // Apply quick fix |
| String before = document.get(); |
| proposal.apply(document); |
| String after = document.get(); |
| String diff = getDiff(before, after); |
| assertEqualsGolden(name, diff); |
| } |
| } |