1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.build; 18 19 import com.android.ide.eclipse.adt.AdtConstants; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest; 22 23 import org.eclipse.core.resources.IFile; 24 import org.eclipse.core.resources.IMarker; 25 import org.eclipse.core.resources.IProject; 26 import org.eclipse.core.resources.IResource; 27 28 import java.io.File; 29 import java.util.Collections; 30 import java.util.List; 31 32 public class AaptParserTest extends AdtProjectTest { 33 34 public void testBasic() throws Exception { 35 // Test the "at 'property' with value 'value' range matching included with most aapt errors 36 checkRanges("quickfix1.xml", "res/layout/quickfix1.xml", 37 "quickfix1.xml:7: error: Error: No resource found that matches the given name (at" 38 + " 'text' with value '@string/firststring').", 39 "android:text=\"^@string/firststring\"", 40 "android:text=\"@string/firststring^\""); 41 } 42 43 public void testRange1() throws Exception { 44 // Check that when the actual aapt error occurs on a line later than the original error 45 // line, the forward search which looks for a value match does not stop on an 46 // earlier line that happens to have the same value prefix 47 checkRanges("aapterror1.xml", "res/layout/aapterror1.xml", 48 "aapterror1.xml:5: error: Error: Integer types not allowed (at " 49 + "'layout_marginBottom' with value '50').", 50 "marginBottom=\"^50\"", "marginBottom=\"50^\""); 51 } 52 53 public void testRange2() throws Exception { 54 // Check that when we have a duplicate resource error, we highlight both the original 55 // property and the original definition. 56 // This tests the second, duplicate declaration ration. 57 checkRanges("aapterror2.xml", "res/values/aapterror2.xml", 58 "aapterror2.xml:7: error: Resource entry repeatedStyle1 already has bag item " 59 + "android:gravity.", 60 "<item name=\"^android:gravity\">bottom</item>", 61 "<item name=\"android:gravity^\">bottom</item>"); 62 } 63 64 public void testRange3() throws Exception { 65 // Check that when we have a duplicate resource error, we highlight both the original 66 // property and the original definition. 67 // This tests the original definition. Note that we don't have enough position info 68 // so we simply highlight the whitespace portion of the line. 69 checkRanges("aapterror2.xml", "res/values/aapterror2.xml", 70 "aapterror2.xml:4: Originally defined here.", 71 "^<item name=\"android:gravity\">left</item>", 72 "<item name=\"android:gravity\">left</item>^"); 73 } 74 75 public void testRange4() throws Exception { 76 // Check for aapt error which occurs when the attribute name in an item style declaration 77 // is nonexistent 78 checkRanges("aapterror3.xml", "res/values/aapterror3.xml", 79 "aapterror3.xml:4: error: Error: No resource found that matches the given name: " 80 + "attr 'nonexistent'.", 81 "<item name=\"^nonexistent\">5</item>", 82 "<item name=\"nonexistent^\">5</item>"); 83 } 84 85 public void testRange5() throws Exception { 86 // Test missing resource name 87 checkRanges("aapterror4.xml", "res/values/aapterror4.xml", 88 "aapterror4.xml:3: error: A 'name' attribute is required for <style>", 89 "<^style>", 90 "<style^>"); 91 } 92 93 public void testRange6() throws Exception { 94 checkRanges("aapterror4.xml", "res/values/aapterror4.xml", 95 "aapterror4.xml:6: error: A 'type' attribute is required for <item>", 96 "<^item></item>", 97 "<item^></item>"); 98 } 99 100 public void testRange7() throws Exception { 101 // Test missing resource name 102 checkRanges("aapterror4.xml", "res/values/aapterror4.xml", 103 "aapterror4.xml:6: error: A 'name' attribute is required for <item>", 104 "<^item></item>", 105 "<item^></item>"); 106 } 107 108 // This test is disabled because I can't find a useful scenario for handling this error 109 // message. When this error occurs, we will also get a warning on a missing attribute, and 110 // that warning already underlines the element name. 111 //public void testRange8() throws Exception { 112 // // Test missing resource name 113 // checkRanges("aapterror4.xml", "res/values/aapterror4.xml", 114 // "aapterror4.xml:4: error: Error: Resource id cannot be an empty string: attr ''.", 115 // " ^<item />", 116 // " <item />^"); 117 //} 118 119 public void testRange9() throws Exception { 120 // Test missing resource name 121 checkRanges("aapterror5.xml", "res/values/aapterror5.xml", 122 "aapterror5.xml:4: error: Error: String types not allowed (at " 123 + "'android:layout_width' with value '').", 124 " <item name=\"^android:layout_width\"></item>", 125 " <item name=\"android:layout_width^\"></item>"); 126 } 127 128 public void testRange10() throws Exception { 129 // Test missing resource name 130 checkRanges("aapterror6.xml", "res/layout/aapterror6.xml", 131 "aapterror6.xml:5: error: Error: String types not allowed (at 'layout_marginTop'" 132 + " with value '').", 133 "android:layout_marginTop=^\"\"", 134 "android:layout_marginTop=\"\"^"); 135 } 136 137 public void testRange11() throws Exception { 138 // Test missing resource name 139 checkRanges("aapterror6.xml", "res/layout/aapterror6.xml", 140 "aapterror1.xml:5: error: Error: String types not allowed (at 'layout_marginLeft'" 141 + " with value '').", 142 "android:layout_marginLeft=^''", 143 "android:layout_marginLeft=''^"); 144 } 145 146 public void testRange12() throws Exception { 147 // Test missing resource name 148 checkRanges("aapterror7.xml", "res/layout/aapterror7.xml", 149 "aapterror7.xml:5: error: Error: String types not allowed (at 'id'" 150 + " with value '').", 151 "android:id=^\"\"", 152 "android:id=\"\"^"); 153 } 154 155 private void checkRanges(String name, String destPath, String aaptError, 156 String expectCaretBegin, String expectCaretEnd) 157 throws Exception { 158 IProject project = getProject(); 159 IFile file = getTestDataFile(project, name, destPath); 160 161 // Make file paths absolute 162 String osRoot = project.getLocation().toOSString(); 163 String fileRelativePath = file.getProjectRelativePath().toPortableString(); 164 String filePath = osRoot + File.separator + fileRelativePath; 165 String originalError = filePath + aaptError.substring(aaptError.indexOf(':')); 166 List<String> errors = Collections.singletonList(originalError); 167 168 // Remove anything already placed there by the project create/build automatic 169 // (this usually only happens while debugging so the background thread has a chance 170 // to get things going) 171 IMarker[] markers = file.findMarkers(AdtConstants.MARKER_AAPT_COMPILE, true, 172 IResource.DEPTH_ZERO); 173 for (IMarker marker : markers) { 174 marker.delete(); 175 } 176 177 AaptParser.parseOutput(errors, project); 178 markers = file.findMarkers(AdtConstants.MARKER_AAPT_COMPILE, true, 179 IResource.DEPTH_ZERO); 180 assertNotNull(markers); 181 assertEquals(1, markers.length); 182 183 String fileContents = AdtPlugin.readFile(file); 184 int rangeBegin = getCaretOffset(file, expectCaretBegin); 185 int rangeEnd = getCaretOffset(file, expectCaretEnd); 186 187 // Check text range 188 IMarker marker = markers[0]; 189 String message = marker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$ 190 String simplerMessage = aaptError.substring(aaptError.indexOf(' ') + 1); 191 assertEquals(simplerMessage, message); 192 int start = marker.getAttribute(IMarker.CHAR_START, 0); 193 int end = marker.getAttribute(IMarker.CHAR_END, 0); 194 195 assertEquals("Wrong start offset, expected " + expectCaretBegin + " but was " 196 + getCaretContext(fileContents, start), rangeBegin, start); 197 assertEquals("Wrong end offset, expected " + expectCaretEnd + " but was " 198 + getCaretContext(fileContents, end), rangeEnd, end); 199 } 200 } 201