• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 package com.android.cts.core.runner;
18 
19 import android.support.test.internal.runner.ClassPathScanner;
20 import android.support.test.internal.runner.ClassPathScanner.ClassNameFilter;
21 import android.util.Log;
22 
23 import com.android.cts.core.internal.runner.TestLoader;
24 
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Enumeration;
29 import java.util.List;
30 import java.util.Set;
31 
32 import dalvik.system.DexFile;
33 
34 /**
35  * Find tests in the current APK.
36  */
37 public class TestClassFinder {
38 
39     private static final String TAG = "TestClassFinder";
40     private static final boolean DEBUG = false;
41 
42     // Excluded test packages
43     private static final String[] DEFAULT_EXCLUDED_PACKAGES = {
44             "junit",
45             "org.junit",
46             "org.hamcrest",
47             "org.mockito",// exclude Mockito for performance and to prevent JVM related errors
48             "android.support.test.internal.runner.junit3",// always skip AndroidTestSuite
49     };
50 
getClasses(List<String> apks, ClassLoader loader)51     static Collection<Class<?>> getClasses(List<String> apks, ClassLoader loader) {
52         if (DEBUG) {
53           Log.d(TAG, "getClasses: =======================================");
54 
55           for (String apkPath : apks) {
56             Log.d(TAG, "getClasses: -------------------------------");
57             Log.d(TAG, "getClasses: APK " + apkPath);
58 
59             DexFile dexFile = null;
60             try {
61                 dexFile = new DexFile(apkPath);
62                 Enumeration<String> apkClassNames = dexFile.entries();
63                 while (apkClassNames.hasMoreElements()) {
64                     String apkClassName = apkClassNames.nextElement();
65                     Log.d(TAG, "getClasses: DexClass element " + apkClassName);
66                 }
67             } catch (IOException e) {
68               throw new AssertionError(e);
69             } finally {
70                 if (dexFile != null) {
71                   try {
72                     dexFile.close();
73                   } catch (IOException e) {
74                     throw new AssertionError(e);
75                   }
76                 }
77             }
78             Log.d(TAG, "getClasses: -------------------------------");
79           }
80         }  // if DEBUG
81 
82         List<Class<?>> classes = new ArrayList<>();
83         ClassPathScanner scanner = new ClassPathScanner(apks);
84 
85         ClassPathScanner.ChainedClassNameFilter filter =
86                 new ClassPathScanner.ChainedClassNameFilter();
87         // exclude inner classes
88         filter.add(new ClassPathScanner.ExternalClassNameFilter());
89 
90         // exclude default classes
91         for (String defaultExcludedPackage : DEFAULT_EXCLUDED_PACKAGES) {
92             filter.add(new ExcludePackageNameFilter(defaultExcludedPackage));
93         }
94 
95         // exclude any classes that aren't a "test class" (see #loadIfTest)
96         TestLoader testLoader = new TestLoader();
97         testLoader.setClassLoader(loader);
98 
99         try {
100             Set<String> classNames = scanner.getClassPathEntries(filter);
101             for (String className : classNames) {
102                 // Important: This further acts as an additional filter;
103                 // classes that aren't a "test class" are never loaded.
104                 Class<?> cls = testLoader.loadIfTest(className);
105                 if (cls != null) {
106                     classes.add(cls);
107 
108                     if (DEBUG) {
109                       Log.d(TAG, "getClasses: Loaded " + className);
110                     }
111                 } else if (DEBUG) {
112                   Log.d(TAG, "getClasses: Failed to load class " + className);
113                 }
114             }
115             return classes;
116         } catch (IOException e) {
117             Log.e(CoreTestRunner.TAG, "Failed to scan classes", e);
118         }
119 
120 
121         if (DEBUG) {
122             Log.d(TAG, "getClasses: =======================================");
123         }
124 
125         return testLoader.getLoadedClasses();
126     }
127 
128     /**
129      * A {@link ClassNameFilter} that only rejects a given package names within the given namespace.
130      */
131     public static class ExcludePackageNameFilter implements ClassNameFilter {
132 
133         private final String mPkgName;
134 
ExcludePackageNameFilter(String pkgName)135         ExcludePackageNameFilter(String pkgName) {
136             if (!pkgName.endsWith(".")) {
137                 mPkgName = String.format("%s.", pkgName);
138             } else {
139                 mPkgName = pkgName;
140             }
141         }
142 
143         /**
144          * {@inheritDoc}
145          */
146         @Override
accept(String pathName)147         public boolean accept(String pathName) {
148             return !pathName.startsWith(mPkgName);
149         }
150     }
151 }
152