1 /* 2 * Copyright (C) 2011 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 package com.android.tradefed.util; 17 18 import com.android.ddmlib.Log; 19 import com.android.tradefed.util.ClassPathScanner.ExternalClassNameFilter; 20 21 import junit.framework.JUnit4TestAdapter; 22 import junit.framework.Test; 23 import junit.framework.TestCase; 24 import junit.framework.TestSuite; 25 26 import org.junit.runners.Suite.SuiteClasses; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.lang.reflect.Method; 31 import java.net.MalformedURLException; 32 import java.net.URL; 33 import java.net.URLClassLoader; 34 import java.util.Collection; 35 import java.util.Iterator; 36 import java.util.Set; 37 38 /** 39 * A class for loading all JUnit3 tests in a jar file 40 */ 41 public class TestLoader { 42 43 private static final String LOG_TAG = "TestLoader"; 44 45 /** 46 * Creates a {@link Test} containing all the {@link TestCase} found in given jar 47 * 48 * @param testJarFile the jar file to load tests from 49 * @param dependentJars the additional jar files which classes in testJarFile depend on 50 * @return the {@link Test} containing all tests 51 */ loadTests(File testJarFile, Collection<File> dependentJars)52 public Test loadTests(File testJarFile, Collection<File> dependentJars) { 53 ClassPathScanner scanner = new ClassPathScanner(); 54 try { 55 Set<String> classNames = 56 scanner.getEntriesFromJar(testJarFile, new ExternalClassNameFilter()).keySet(); 57 58 URLClassLoader jarClassLoader = buildJarClassLoader(testJarFile, dependentJars); 59 try { 60 return loadTests(classNames, jarClassLoader); 61 } finally { 62 jarClassLoader.close(); 63 } 64 } catch (IOException e) { 65 Log.e(LOG_TAG, String.format("IOException when loading test classes from jar %s", 66 testJarFile.getAbsolutePath())); 67 Log.e(LOG_TAG, e); 68 } 69 return null; 70 } 71 buildJarClassLoader(File jarFile, Collection<File> dependentJars)72 private URLClassLoader buildJarClassLoader(File jarFile, Collection<File> dependentJars) 73 throws MalformedURLException { 74 URL[] urls = new URL[dependentJars.size() + 1]; 75 urls[0] = jarFile.toURI().toURL(); 76 Iterator<File> jarIter = dependentJars.iterator(); 77 for (int i=1; i <= dependentJars.size(); i++) { 78 urls[i] = jarIter.next().toURI().toURL(); 79 } 80 return new URLClassLoader(urls); 81 } 82 83 @SuppressWarnings("unchecked") loadTests(Set<String> classNames, ClassLoader classLoader)84 private Test loadTests(Set<String> classNames, ClassLoader classLoader) { 85 TestSuite testSuite = new TestSuite(); 86 for (String className : classNames) { 87 try { 88 Class<?> testClass = Class.forName(className, true, classLoader); 89 if (TestCase.class.isAssignableFrom(testClass)) { 90 testSuite.addTestSuite((Class<? extends TestCase>)testClass); 91 } else if (hasJUnit4Annotation(testClass)) { 92 testSuite.addTest(new JUnit4TestAdapter(testClass)); 93 } 94 } catch (NoClassDefFoundError e) { 95 Log.e(LOG_TAG, e); 96 } catch (ClassNotFoundException e) { 97 Log.e(LOG_TAG, e); 98 } catch (RuntimeException e) { 99 // catch this to prevent one bad test from stopping run 100 Log.e(LOG_TAG, e); 101 } 102 } 103 return testSuite; 104 } 105 106 /** 107 * Helper to device if a class should be loaded as JUnit4. 108 */ hasJUnit4Annotation(Class<?> classObj)109 private boolean hasJUnit4Annotation(Class<?> classObj) { 110 if (classObj.isAnnotationPresent(SuiteClasses.class)) { 111 return true; 112 } 113 for (Method m : classObj.getMethods()) { 114 if (m.isAnnotationPresent(org.junit.Test.class)) { 115 return true; 116 } 117 } 118 return false; 119 } 120 } 121