Merge "Clean up ClassPathPackageInfoSource" am: 8c7026c5a3 am: 1c6a5ad92e
am: 88d54c3080
Change-Id: I3716fc728a6789a33851f4f0ad30a3ad9f421a17
This commit is contained in:
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* 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 android.test;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Package object doesn't allow you to iterate over the contained
|
|
||||||
* classes and subpackages of that package. This is a version that does.
|
|
||||||
*
|
|
||||||
* {@hide} Not needed for 1.0 SDK.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class ClassPathPackageInfo {
|
|
||||||
|
|
||||||
private final ClassPathPackageInfoSource source;
|
|
||||||
private final String packageName;
|
|
||||||
private final Set<String> subpackageNames;
|
|
||||||
private final Set<Class<?>> topLevelClasses;
|
|
||||||
|
|
||||||
ClassPathPackageInfo(ClassPathPackageInfoSource source, String packageName,
|
|
||||||
Set<String> subpackageNames, Set<Class<?>> topLevelClasses) {
|
|
||||||
this.source = source;
|
|
||||||
this.packageName = packageName;
|
|
||||||
this.subpackageNames = Collections.unmodifiableSet(subpackageNames);
|
|
||||||
this.topLevelClasses = Collections.unmodifiableSet(topLevelClasses);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<ClassPathPackageInfo> getSubpackages() {
|
|
||||||
Set<ClassPathPackageInfo> info = new HashSet<>();
|
|
||||||
for (String name : subpackageNames) {
|
|
||||||
info.add(source.getPackageInfo(name));
|
|
||||||
}
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Class<?>> getTopLevelClassesRecursive() {
|
|
||||||
Set<Class<?>> set = new HashSet<>();
|
|
||||||
addTopLevelClassesTo(set);
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTopLevelClassesTo(Set<Class<?>> set) {
|
|
||||||
set.addAll(topLevelClasses);
|
|
||||||
for (ClassPathPackageInfo info : getSubpackages()) {
|
|
||||||
info.addTopLevelClassesTo(set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj instanceof ClassPathPackageInfo) {
|
|
||||||
ClassPathPackageInfo that = (ClassPathPackageInfo) obj;
|
|
||||||
return (this.packageName).equals(that.packageName);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return packageName.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,15 +21,12 @@ import dalvik.system.DexFile;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate {@link ClassPathPackageInfo}s by scanning apk paths.
|
* Generate {@link ClassPathPackageInfo}s by scanning apk paths.
|
||||||
@@ -39,11 +36,13 @@ import java.util.zip.ZipFile;
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public class ClassPathPackageInfoSource {
|
public class ClassPathPackageInfoSource {
|
||||||
|
|
||||||
private static final String CLASS_EXTENSION = ".class";
|
|
||||||
|
|
||||||
private static final ClassLoader CLASS_LOADER
|
private static final ClassLoader CLASS_LOADER
|
||||||
= ClassPathPackageInfoSource.class.getClassLoader();
|
= ClassPathPackageInfoSource.class.getClassLoader();
|
||||||
|
|
||||||
|
private static String[] apkPaths;
|
||||||
|
|
||||||
|
private static ClassPathPackageInfoSource classPathSource;
|
||||||
|
|
||||||
private final SimpleCache<String, ClassPathPackageInfo> cache =
|
private final SimpleCache<String, ClassPathPackageInfo> cache =
|
||||||
new SimpleCache<String, ClassPathPackageInfo>() {
|
new SimpleCache<String, ClassPathPackageInfo>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -54,23 +53,28 @@ public class ClassPathPackageInfoSource {
|
|||||||
|
|
||||||
// The class path of the running application
|
// The class path of the running application
|
||||||
private final String[] classPath;
|
private final String[] classPath;
|
||||||
private static String[] apkPaths;
|
|
||||||
|
|
||||||
// A cache of jar file contents
|
private final ClassLoader classLoader;
|
||||||
private final Map<File, Set<String>> jarFiles = new HashMap<>();
|
|
||||||
private ClassLoader classLoader;
|
|
||||||
|
|
||||||
ClassPathPackageInfoSource() {
|
private ClassPathPackageInfoSource(ClassLoader classLoader) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
classPath = getClassPath();
|
classPath = getClassPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setApkPaths(String[] apkPaths) {
|
||||||
public static void setApkPaths(String[] apkPaths) {
|
|
||||||
ClassPathPackageInfoSource.apkPaths = apkPaths;
|
ClassPathPackageInfoSource.apkPaths = apkPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassPathPackageInfo getPackageInfo(String pkgName) {
|
public static ClassPathPackageInfoSource forClassPath(ClassLoader classLoader) {
|
||||||
return cache.get(pkgName);
|
if (classPathSource == null) {
|
||||||
|
classPathSource = new ClassPathPackageInfoSource(classLoader);
|
||||||
|
}
|
||||||
|
return classPathSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Class<?>> getTopLevelClassesRecursive(String packageName) {
|
||||||
|
ClassPathPackageInfo packageInfo = cache.get(packageName);
|
||||||
|
return packageInfo.getTopLevelClassesRecursive();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassPathPackageInfo createPackageInfo(String packageName) {
|
private ClassPathPackageInfo createPackageInfo(String packageName) {
|
||||||
@@ -96,7 +100,7 @@ public class ClassPathPackageInfoSource {
|
|||||||
+ "'. Message: " + e.getMessage(), e);
|
+ "'. Message: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ClassPathPackageInfo(this, packageName, subpackageNames,
|
return new ClassPathPackageInfo(packageName, subpackageNames,
|
||||||
topLevelClasses);
|
topLevelClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +111,6 @@ public class ClassPathPackageInfoSource {
|
|||||||
*/
|
*/
|
||||||
private void findClasses(String packageName, Set<String> classNames,
|
private void findClasses(String packageName, Set<String> classNames,
|
||||||
Set<String> subpackageNames) {
|
Set<String> subpackageNames) {
|
||||||
String packagePrefix = packageName + '.';
|
|
||||||
String pathPrefix = packagePrefix.replace('.', '/');
|
|
||||||
|
|
||||||
for (String entryName : classPath) {
|
for (String entryName : classPath) {
|
||||||
File classPathEntry = new File(entryName);
|
File classPathEntry = new File(entryName);
|
||||||
|
|
||||||
@@ -148,58 +149,6 @@ public class ClassPathPackageInfoSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds all classes and sub packages that are below the packageName and
|
|
||||||
* add them to the respective sets. Searches the package in a class directory.
|
|
||||||
*/
|
|
||||||
private void findClassesInDirectory(File classDir,
|
|
||||||
String packagePrefix, String pathPrefix, Set<String> classNames,
|
|
||||||
Set<String> subpackageNames)
|
|
||||||
throws IOException {
|
|
||||||
File directory = new File(classDir, pathPrefix);
|
|
||||||
|
|
||||||
if (directory.exists()) {
|
|
||||||
for (File f : directory.listFiles()) {
|
|
||||||
String name = f.getName();
|
|
||||||
if (name.endsWith(CLASS_EXTENSION) && isToplevelClass(name)) {
|
|
||||||
classNames.add(packagePrefix + getClassName(name));
|
|
||||||
} else if (f.isDirectory()) {
|
|
||||||
subpackageNames.add(packagePrefix + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds all classes and sub packages that are below the packageName and
|
|
||||||
* add them to the respective sets. Searches the package in a single jar file.
|
|
||||||
*/
|
|
||||||
private void findClassesInJar(File jarFile, String pathPrefix,
|
|
||||||
Set<String> classNames, Set<String> subpackageNames)
|
|
||||||
throws IOException {
|
|
||||||
Set<String> entryNames = getJarEntries(jarFile);
|
|
||||||
// check if the Jar contains the package.
|
|
||||||
if (!entryNames.contains(pathPrefix)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int prefixLength = pathPrefix.length();
|
|
||||||
for (String entryName : entryNames) {
|
|
||||||
if (entryName.startsWith(pathPrefix)) {
|
|
||||||
if (entryName.endsWith(CLASS_EXTENSION)) {
|
|
||||||
// check if the class is in the package itself or in one of its
|
|
||||||
// subpackages.
|
|
||||||
int index = entryName.indexOf('/', prefixLength);
|
|
||||||
if (index >= 0) {
|
|
||||||
String p = entryName.substring(0, index).replace('/', '.');
|
|
||||||
subpackageNames.add(p);
|
|
||||||
} else if (isToplevelClass(entryName)) {
|
|
||||||
classNames.add(getClassName(entryName).replace('/', '.'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all classes and sub packages that are below the packageName and
|
* Finds all classes and sub packages that are below the packageName and
|
||||||
* add them to the respective sets. Searches the package in a single apk file.
|
* add them to the respective sets. Searches the package in a single apk file.
|
||||||
@@ -241,47 +190,6 @@ public class ClassPathPackageInfoSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the class and package entries from a Jar.
|
|
||||||
*/
|
|
||||||
private Set<String> getJarEntries(File jarFile)
|
|
||||||
throws IOException {
|
|
||||||
Set<String> entryNames = jarFiles.get(jarFile);
|
|
||||||
if (entryNames == null) {
|
|
||||||
entryNames = new HashSet<>();
|
|
||||||
ZipFile zipFile = new ZipFile(jarFile);
|
|
||||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
String entryName = entries.nextElement().getName();
|
|
||||||
if (entryName.endsWith(CLASS_EXTENSION)) {
|
|
||||||
// add the entry name of the class
|
|
||||||
entryNames.add(entryName);
|
|
||||||
|
|
||||||
// add the entry name of the classes package, i.e. the entry name of
|
|
||||||
// the directory that the class is in. Used to quickly skip jar files
|
|
||||||
// if they do not contain a certain package.
|
|
||||||
//
|
|
||||||
// Also add parent packages so that a JAR that contains
|
|
||||||
// pkg1/pkg2/Foo.class will be marked as containing pkg1/ in addition
|
|
||||||
// to pkg1/pkg2/ and pkg1/pkg2/Foo.class. We're still interested in
|
|
||||||
// JAR files that contains subpackages of a given package, even if
|
|
||||||
// an intermediate package contains no direct classes.
|
|
||||||
//
|
|
||||||
// Classes in the default package will cause a single package named
|
|
||||||
// "" to be added instead.
|
|
||||||
int lastIndex = entryName.lastIndexOf('/');
|
|
||||||
do {
|
|
||||||
String packageName = entryName.substring(0, lastIndex + 1);
|
|
||||||
entryNames.add(packageName);
|
|
||||||
lastIndex = entryName.lastIndexOf('/', lastIndex - 1);
|
|
||||||
} while (lastIndex > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jarFiles.put(jarFile, entryNames);
|
|
||||||
}
|
|
||||||
return entryNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a given file name represents a toplevel class.
|
* Checks if a given file name represents a toplevel class.
|
||||||
*/
|
*/
|
||||||
@@ -289,14 +197,6 @@ public class ClassPathPackageInfoSource {
|
|||||||
return fileName.indexOf('$') < 0;
|
return fileName.indexOf('$') < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given the absolute path of a class file, return the class name.
|
|
||||||
*/
|
|
||||||
private static String getClassName(String className) {
|
|
||||||
int classNameEnd = className.length() - CLASS_EXTENSION.length();
|
|
||||||
return className.substring(0, classNameEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the class path from the System Property "java.class.path" and splits
|
* Gets the class path from the System Property "java.class.path" and splits
|
||||||
* it up into the individual elements.
|
* it up into the individual elements.
|
||||||
@@ -307,7 +207,56 @@ public class ClassPathPackageInfoSource {
|
|||||||
return classPath.split(Pattern.quote(separator));
|
return classPath.split(Pattern.quote(separator));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setClassLoader(ClassLoader classLoader) {
|
/**
|
||||||
this.classLoader = classLoader;
|
* The Package object doesn't allow you to iterate over the contained
|
||||||
|
* classes and subpackages of that package. This is a version that does.
|
||||||
|
*/
|
||||||
|
private class ClassPathPackageInfo {
|
||||||
|
|
||||||
|
private final String packageName;
|
||||||
|
private final Set<String> subpackageNames;
|
||||||
|
private final Set<Class<?>> topLevelClasses;
|
||||||
|
|
||||||
|
private ClassPathPackageInfo(String packageName,
|
||||||
|
Set<String> subpackageNames, Set<Class<?>> topLevelClasses) {
|
||||||
|
this.packageName = packageName;
|
||||||
|
this.subpackageNames = Collections.unmodifiableSet(subpackageNames);
|
||||||
|
this.topLevelClasses = Collections.unmodifiableSet(topLevelClasses);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<ClassPathPackageInfo> getSubpackages() {
|
||||||
|
Set<ClassPathPackageInfo> info = new HashSet<>();
|
||||||
|
for (String name : subpackageNames) {
|
||||||
|
info.add(cache.get(name));
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Class<?>> getTopLevelClassesRecursive() {
|
||||||
|
Set<Class<?>> set = new HashSet<>();
|
||||||
|
addTopLevelClassesTo(set);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTopLevelClassesTo(Set<Class<?>> set) {
|
||||||
|
set.addAll(topLevelClasses);
|
||||||
|
for (ClassPathPackageInfo info : getSubpackages()) {
|
||||||
|
info.addTopLevelClassesTo(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof ClassPathPackageInfo) {
|
||||||
|
ClassPathPackageInfo that = (ClassPathPackageInfo) obj;
|
||||||
|
return (this.packageName).equals(that.packageName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return packageName.hashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* 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 android.test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@hide} Not needed for SDK.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class PackageInfoSources {
|
|
||||||
|
|
||||||
private static ClassPathPackageInfoSource classPathSource;
|
|
||||||
|
|
||||||
private PackageInfoSources() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ClassPathPackageInfoSource forClassPath(ClassLoader classLoader) {
|
|
||||||
if (classPathSource == null) {
|
|
||||||
classPathSource = new ClassPathPackageInfoSource();
|
|
||||||
classPathSource.setClassLoader(classLoader);
|
|
||||||
}
|
|
||||||
return classPathSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
package android.test.suitebuilder;
|
package android.test.suitebuilder;
|
||||||
|
|
||||||
import android.test.ClassPathPackageInfo;
|
|
||||||
import android.test.ClassPathPackageInfoSource;
|
import android.test.ClassPathPackageInfoSource;
|
||||||
import android.test.PackageInfoSources;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.android.internal.util.Predicate;
|
import com.android.internal.util.Predicate;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
@@ -131,10 +129,9 @@ class TestGrouping {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Class<? extends TestCase>> testCaseClassesInPackage(String packageName) {
|
private List<Class<? extends TestCase>> testCaseClassesInPackage(String packageName) {
|
||||||
ClassPathPackageInfoSource source = PackageInfoSources.forClassPath(classLoader);
|
ClassPathPackageInfoSource source = ClassPathPackageInfoSource.forClassPath(classLoader);
|
||||||
ClassPathPackageInfo packageInfo = source.getPackageInfo(packageName);
|
|
||||||
|
|
||||||
return selectTestClasses(packageInfo.getTopLevelClassesRecursive());
|
return selectTestClasses(source.getTopLevelClassesRecursive(packageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ include $(CLEAR_VARS)
|
|||||||
# We only want this apk build for tests.
|
# We only want this apk build for tests.
|
||||||
#
|
#
|
||||||
# Run the tests using the following commands:
|
# Run the tests using the following commands:
|
||||||
# adb -r install ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
|
# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
|
||||||
# adb shell am instrument \
|
# adb shell am instrument \
|
||||||
-e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
|
-e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
|
||||||
-w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner
|
-w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner
|
||||||
|
|||||||
Reference in New Issue
Block a user