in tools/device_broker/java/com/google/android/apps/common/testing/suite/dex/DumpUtils.java [311:419]
public static TestSuitePb discoverTests(Iterator<DexClassData> dexIterator) {
Map<String, SettableFuture<Optional<TestRelatedClassData>>> classNameToTestData =
Maps.newHashMap();
SettableFuture<Optional<TestRelatedClassData>> javaLangObject = SettableFuture.create();
javaLangObject.set(Optional.<TestRelatedClassData>absent());
classNameToTestData.put("java.lang.Object", javaLangObject);
while (dexIterator.hasNext()) {
DexClassData data = dexIterator.next();
SettableFuture<Optional<TestRelatedClassData>> myTestData = classNameToTestData.get(
data.getFullClassName());
if (null == myTestData) {
// no one has depended on us as a parent class yet. but they might!
myTestData = SettableFuture.create();
classNameToTestData.put(data.getFullClassName(), myTestData);
}
checkState(!myTestData.isDone(), "Impossible! I'm responsible for creating this! %s",
data.getFullClassName());
if (hasAnnotationDefaultData(data)) {
// this must be an annotation class - and it has a default value.
// we'll need this to properly populate TestInfo proto buffers.
TestRelatedClassData annoData = new TestRelatedClassData(false);
annoData.defaultAnnotationData = Optional.of(extractAnnotationDefault(data));
myTestData.set(Optional.of(annoData));
} else if (data.getFullClassName().equals("junit.framework.TestCase")) {
// our base case! the class everyone must extend to be a j3 class.
TestRelatedClassData junit3TestData = new TestRelatedClassData(true);
// obviously has no test methods and is not executable in and of itself,
// however this will trigger its decendants listeners.
// this is provably not a junit descendant (eg: extends something in java).
myTestData.set(Optional.of(junit3TestData));
} else {
// We need to determine whether we're a decendant of junit3 test case.
// we do that by listening to our parent's future to see if it has
// any TestRelatedClassData.
SettableFuture<Optional<TestRelatedClassData>> parentTestData = classNameToTestData.get(
data.getExtendsClass());
if (null == parentTestData) {
parentTestData = SettableFuture.create();
classNameToTestData.put(data.getExtendsClass(), parentTestData);
}
parentTestData.addListener(new OnParentTestRelatedDataListener(data, myTestData,
parentTestData), MoreExecutors.directExecutor());
}
}
// Lets get all the test related data that we discovered
List<TestRelatedClassData> testData =
FluentIterable.from(classNameToTestData.values())
.filter(COMPUTATION_COMPLETE)
.transform(
new Function<
Future<Optional<TestRelatedClassData>>, Optional<TestRelatedClassData>>() {
@Override
public Optional<TestRelatedClassData> apply(
Future<Optional<TestRelatedClassData>> futureIn) {
try {
return futureIn.get();
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
} catch (ExecutionException ee) {
throwIfUnchecked(ee.getCause());
throw new RuntimeException(ee.getCause());
}
}
})
.filter(OPTION_PRESENT)
.transform(DumpUtils.<TestRelatedClassData>removeOptionality())
.toList();
// Build a map of annotations to their defaults
Map<String, AnnotationPb> defaultAnnotations =
FluentIterable
.from(testData)
.transform(new Function<TestRelatedClassData, Optional<AnnotationPb>>() {
@Override
public Optional<AnnotationPb> apply(TestRelatedClassData dataIn) {
return dataIn.defaultAnnotationData;
}
})
.filter(OPTION_PRESENT)
.transform(DumpUtils.<AnnotationPb>removeOptionality())
.uniqueIndex(EXTRACT_ANNOTATION_CLASS_NAME);
// Get all the tests (and apply annotation defaults where needed)
List<InfoPb> allExecutableTests =
FluentIterable
.from(testData)
.transform(new Function<TestRelatedClassData, Optional<List<InfoPb>>>() {
@Override
public Optional<List<InfoPb>> apply(TestRelatedClassData dataIn) {
return dataIn.executableTests;
}
})
.filter(OPTION_PRESENT)
.transformAndConcat(DumpUtils.<List<InfoPb>>removeOptionality())
.transform(new MergeWithDefaultAnnotations(defaultAnnotations))
.toList();
return TestSuitePb.newBuilder().addAllInfo(allExecutableTests).build();
}