public static TestSuitePb discoverTests()

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();
  }