1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 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 import java.io.BufferedReader; 18 import java.io.File; 19 import java.io.FileInputStream; 20 import java.io.FileReader; 21 import java.io.IOException; 22 import java.lang.annotation.Annotation; 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 import java.util.ArrayList; 26 import java.util.HashSet; 27 import java.util.Iterator; 28 import java.util.LinkedHashMap; 29 import java.util.Map; 30 import java.util.Set; 31 32 import javax.xml.parsers.DocumentBuilderFactory; 33 import javax.xml.parsers.ParserConfigurationException; 34 35 import junit.framework.Test; 36 import junit.framework.TestCase; 37 import junit.framework.TestResult; 38 import junit.textui.ResultPrinter; 39 import junit.textui.TestRunner; 40 41 import org.w3c.dom.Document; 42 import org.w3c.dom.Element; 43 import org.w3c.dom.Node; 44 import org.w3c.dom.NodeList; 45 46 public class CollectAllTests extends DescriptionGenerator { 47 48 static final String ATTRIBUTE_RUNNER = "runner"; 49 static final String ATTRIBUTE_PACKAGE = "appPackageName"; 50 static final String ATTRIBUTE_NS = "appNameSpace"; 51 static final String ATTRIBUTE_TARGET = "targetNameSpace"; 52 static final String ATTRIBUTE_TARGET_BINARY = "targetBinaryName"; 53 static final String ATTRIBUTE_HOST_SIDE_ONLY = "hostSideOnly"; 54 static final String ATTRIBUTE_JAR_PATH = "jarPath"; 55 56 static final String JAR_PATH = "LOCAL_JAR_PATH :="; 57 static final String TEST_TYPE = "LOCAL_TEST_TYPE :"; 58 59 static final int HOST_SIDE_ONLY = 1; 60 static final int DEVICE_SIDE_ONLY = 2; 61 62 private static String runner; 63 private static String packageName; 64 private static String target; 65 private static String xmlName; 66 private static int testType; 67 private static String jarPath; 68 69 private static Map<String,TestClass> testCases; 70 private static Set<String> failed = new HashSet<String>(); 71 72 private static class MyXMLGenerator extends XMLGenerator { 73 74 MyXMLGenerator(String outputPath) throws ParserConfigurationException { 75 super(outputPath); 76 77 Node testPackageElem = mDoc.getDocumentElement(); 78 79 setAttribute(testPackageElem, ATTRIBUTE_NAME, xmlName); 80 setAttribute(testPackageElem, ATTRIBUTE_RUNNER, runner); 81 setAttribute(testPackageElem, ATTRIBUTE_PACKAGE, packageName); 82 setAttribute(testPackageElem, ATTRIBUTE_NS, packageName); 83 84 if (testType == HOST_SIDE_ONLY) { 85 setAttribute(testPackageElem, ATTRIBUTE_HOST_SIDE_ONLY, "true"); 86 setAttribute(testPackageElem, ATTRIBUTE_JAR_PATH, jarPath); 87 } 88 89 if (!packageName.equals(target)) { 90 setAttribute(testPackageElem, ATTRIBUTE_TARGET, target); 91 setAttribute(testPackageElem, ATTRIBUTE_TARGET_BINARY, target); 92 } 93 } 94 } 95 96 private static String OUTPUTFILE = ""; 97 private static String MANIFESTFILE = ""; 98 private static String TESTSUITECLASS = ""; 99 private static String ANDROID_MAKE_FILE = ""; 100 101 private static Test TESTSUITE; 102 103 static XMLGenerator xmlGenerator; 104 105 public static void main(String[] args) { 106 if (args.length > 2) { 107 OUTPUTFILE = args[0]; 108 MANIFESTFILE = args [1]; 109 TESTSUITECLASS = args[2]; 110 if (args.length > 3) { 111 ANDROID_MAKE_FILE = args[3]; 112 } 113 } else { 114 System.out.println("usage: \n" + 115 "\t... CollectAllTests <output-file> <manifest-file> <testsuite-class-name> <makefile-file>"); 116 System.exit(1); 117 } 118 119 if (ANDROID_MAKE_FILE.length() > 0) { 120 testType = getTestType(ANDROID_MAKE_FILE); 121 } 122 123 Document manifest = null; 124 try { 125 manifest = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new FileInputStream(MANIFESTFILE)); 126 } catch (Exception e) { 127 System.err.println("cannot open manifest"); 128 e.printStackTrace(); 129 System.exit(1);; 130 } 131 132 Element documentElement = manifest.getDocumentElement(); 133 134 documentElement.getAttribute("package"); 135 136 xmlName = new File(OUTPUTFILE).getName(); 137 runner = getElementAttribute(documentElement, "instrumentation", "android:name"); 138 packageName = documentElement.getAttribute("package"); 139 target = getElementAttribute(documentElement, "instrumentation", "android:targetPackage"); 140 141 Class<?> testClass = null; 142 try { 143 testClass = Class.forName(TESTSUITECLASS); 144 } catch (ClassNotFoundException e) { 145 System.err.println("test class not found"); 146 e.printStackTrace(); 147 System.exit(1);; 148 } 149 150 Method method = null; 151 try { 152 method = testClass.getMethod("suite", new Class<?>[0]); 153 } catch (SecurityException e) { 154 System.err.println("failed to get suite method"); 155 e.printStackTrace(); 156 System.exit(1);; 157 } catch (NoSuchMethodException e) { 158 System.err.println("failed to get suite method"); 159 e.printStackTrace(); 160 System.exit(1);; 161 } 162 163 try { 164 TESTSUITE = (Test) method.invoke(null, (Object[])null); 165 } catch (IllegalArgumentException e) { 166 System.err.println("failed to get suite method"); 167 e.printStackTrace(); 168 System.exit(1);; 169 } catch (IllegalAccessException e) { 170 System.err.println("failed to get suite method"); 171 e.printStackTrace(); 172 System.exit(1);; 173 } catch (InvocationTargetException e) { 174 System.err.println("failed to get suite method"); 175 e.printStackTrace(); 176 System.exit(1);; 177 } 178 179 try { 180 xmlGenerator = new MyXMLGenerator(OUTPUTFILE + ".xml"); 181 } catch (ParserConfigurationException e) { 182 System.err.println("Can't initialize XML Generator"); 183 System.exit(1); 184 } 185 186 testCases = new LinkedHashMap<String, TestClass>(); 187 CollectAllTests cat = new CollectAllTests(); 188 cat.compose(); 189 190 if (!failed.isEmpty()) { 191 System.err.println("The following classes have no default constructor"); 192 for (Iterator<String> iterator = failed.iterator(); iterator.hasNext();) { 193 String type = iterator.next(); 194 System.err.println(type); 195 } 196 System.exit(1); 197 } 198 199 for (Iterator<TestClass> iterator = testCases.values().iterator(); iterator.hasNext();) { 200 TestClass type = iterator.next(); 201 xmlGenerator.addTestClass(type); 202 } 203 204 try { 205 xmlGenerator.dump(); 206 } catch (Exception e) { 207 System.err.println("cannot dump xml"); 208 e.printStackTrace(); 209 System.exit(1); 210 } 211 } 212 213 private static int getTestType(String makeFileName) { 214 215 int type = DEVICE_SIDE_ONLY; 216 try { 217 BufferedReader reader = new BufferedReader(new FileReader(makeFileName)); 218 String line; 219 220 while ((line =reader.readLine())!=null) { 221 if (line.startsWith(TEST_TYPE)) { 222 type = HOST_SIDE_ONLY; 223 } else if (line.startsWith(JAR_PATH)) { 224 jarPath = line.substring(JAR_PATH.length(), line.length()).trim(); 225 } 226 } 227 reader.close(); 228 } catch (IOException e) { 229 } 230 231 return type; 232 } 233 234 private static Element getElement(Element element, String tagName) { 235 NodeList elements = element.getElementsByTagName(tagName); 236 if (elements.getLength() > 0) { 237 return (Element) elements.item(0); 238 } else { 239 return null; 240 } 241 } 242 243 private static String getElementAttribute(Element element, String elementName, String attributeName) { 244 Element e = getElement(element, elementName); 245 if (e != null) { 246 return e.getAttribute(attributeName); 247 } else { 248 return ""; 249 } 250 } 251 252 public void compose() { 253 TestRunner runner = new TestRunner() { 254 @Override 255 protected TestResult createTestResult() { 256 return new TestResult() { 257 @Override 258 protected void run(TestCase test) { 259 addToTests(test); 260 } 261 }; 262 } 263 264 @Override 265 public TestResult doRun(Test test) { 266 return super.doRun(test); 267 } 268 269 270 271 }; 272 273 runner.setPrinter(new ResultPrinter(System.out) { 274 @Override 275 protected void printFooter(TestResult result) { 276 } 277 278 @Override 279 protected void printHeader(long runTime) { 280 } 281 }); 282 runner.doRun(TESTSUITE); 283 } 284 285 private String getKnownFailure(final Class<? extends TestCase> testClass, 286 final String testName) { 287 return getAnnotation(testClass, testName, KNOWN_FAILURE); 288 } 289 290 private boolean isKnownFailure(final Class<? extends TestCase> testClass, 291 final String testName) { 292 return getAnnotation(testClass, testName, KNOWN_FAILURE) != null; 293 } 294 295 private boolean isBrokenTest(final Class<? extends TestCase> testClass, 296 final String testName) { 297 return getAnnotation(testClass, testName, BROKEN_TEST) != null; 298 } 299 300 private boolean isSuppressed(final Class<? extends TestCase> testClass, 301 final String testName) { 302 return getAnnotation(testClass, testName, SUPPRESSED_TEST) != null; 303 } 304 305 private String getAnnotation(final Class<? extends TestCase> testClass, 306 final String testName, final String annotationName) { 307 try { 308 Method testMethod = testClass.getMethod(testName, (Class[])null); 309 Annotation[] annotations = testMethod.getAnnotations(); 310 for (Annotation annot : annotations) { 311 312 if (annot.annotationType().getName().equals(annotationName)) { 313 String annotStr = annot.toString(); 314 String knownFailure = null; 315 if (annotStr.contains("(value=")) { 316 knownFailure = 317 annotStr.substring(annotStr.indexOf("=") + 1, 318 annotStr.length() - 1); 319 320 } 321 322 if (knownFailure == null) { 323 knownFailure = "true"; 324 } 325 326 return knownFailure; 327 } 328 329 } 330 331 } catch (java.lang.NoSuchMethodException e) { 332 } 333 334 return null; 335 } 336 337 private void addToTests(TestCase test) { 338 339 String testClassName = test.getClass().getName(); 340 String testName = test.getName(); 341 String knownFailure = getKnownFailure(test.getClass(), testName); 342 343 if (isKnownFailure(test.getClass(), testName)) { 344 System.out.println("ignoring known failure: " + test); 345 return; 346 } else if (isBrokenTest(test.getClass(), testName)) { 347 System.out.println("ignoring broken test: " + test); 348 return; 349 } else if (isSuppressed(test.getClass(), testName)) { 350 System.out.println("ignoring suppressed test: " + test); 351 return; 352 } 353 354 if (!testName.startsWith("test")) { 355 try { 356 test.runBare(); 357 } catch (Throwable e) { 358 e.printStackTrace(); 359 return; 360 } 361 } 362 TestClass testClass = null; 363 if (testCases.containsKey(testClassName)) { 364 testClass = testCases.get(testClassName); 365 } else { 366 testClass = new TestClass(testClassName, new ArrayList<TestMethod>()); 367 testCases.put(testClassName, testClass); 368 } 369 370 testClass.mCases.add(new TestMethod(testName, "", "", knownFailure, false, false)); 371 372 try { 373 test.getClass().getConstructor(new Class<?>[0]); 374 } catch (SecurityException e) { 375 failed.add(test.getClass().getName()); 376 } catch (NoSuchMethodException e) { 377 failed.add(test.getClass().getName()); 378 } 379 } 380 } 381