1 /*
2  * Copyright (C) 2014 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.compatibility.common.scanner;
18 
19 import com.android.compatibility.common.util.KeyValueArgsParser;
20 
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileFilter;
24 import java.io.InputStreamReader;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.HashMap;
28 import java.util.List;
29 
30 /**
31  * Scans a source directory for java tests and outputs a list of test classes and methods.
32  */
33 public class JavaScanner {
34 
35     static final String[] SOURCE_PATHS = {
36         "./frameworks/base/core/java",
37         "./frameworks/base/test-runner/src",
38         "./external/junit/src",
39         "./development/tools/hosttestlib/src",
40         "./libcore/dalvik/src/main/java",
41         "./common/device-side/util/src",
42         "./common/host-side/tradefed/src",
43         "./common/util/src"
44     };
45     static final String[] CLASS_PATHS = {
46         "./prebuilts/misc/common/tradefed/tradefed-prebuilt.java",
47         "./prebuilts/misc/common/ub-uiautomator/ub-uiautomator.java"
48     };
49     private final File mSourceDir;
50     private final File mDocletDir;
51 
52     /**
53      * @param sourceDir The directory holding the source to scan.
54      * @param docletDir The directory holding the doclet (or its jar).
55      */
JavaScanner(File sourceDir, File docletDir)56     JavaScanner(File sourceDir, File docletDir) {
57         this.mSourceDir = sourceDir;
58         this.mDocletDir = docletDir;
59     }
60 
scan()61     int scan() throws Exception {
62         final ArrayList<String> args = new ArrayList<String>();
63         args.add("javadoc");
64         args.add("-doclet");
65         args.add("com.android.compatibility.common.scanner.JavaScannerDoclet");
66         args.add("-sourcepath");
67         args.add(getSourcePath(mSourceDir));
68         args.add("-classpath");
69         args.add(getClassPath());
70         args.add("-docletpath");
71         args.add(mDocletDir.toString());
72         args.addAll(getSourceFiles(mSourceDir));
73 
74         // Dont want p to get blocked due to a full pipe.
75         final Process p = new ProcessBuilder(args).redirectErrorStream(true).start();
76         final BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
77         try {
78             String line = null;
79             while ((line = in.readLine()) != null) {
80                 if (line.startsWith("suite:") ||
81                     line.startsWith("case:") ||
82                     line.startsWith("test:")) {
83                     System.out.println(line);
84                 }
85             }
86         } finally {
87           if (in != null) {
88               in.close();
89           }
90         }
91 
92         return p.waitFor();
93     }
94 
getSourcePath(File sourceDir)95     private static String getSourcePath(File sourceDir) {
96         final ArrayList<String> sourcePath = new ArrayList<String>(Arrays.asList(SOURCE_PATHS));
97         sourcePath.add(sourceDir.toString());
98         return join(sourcePath, ":");
99     }
100 
getClassPath()101     private static String getClassPath() {
102         return join(Arrays.asList(CLASS_PATHS), ":");
103     }
104 
getSourceFiles(File sourceDir)105     private static ArrayList<String> getSourceFiles(File sourceDir) {
106         final ArrayList<String> sourceFiles = new ArrayList<String>();
107         final File[] files = sourceDir.listFiles(new FileFilter() {
108             public boolean accept(File pathname) {
109                 return pathname.isDirectory() || pathname.toString().endsWith(".java");
110             }
111         });
112         for (File f : files) {
113             if (f.isDirectory()) {
114                 sourceFiles.addAll(getSourceFiles(f));
115             } else {
116                 sourceFiles.add(f.toString());
117             }
118         }
119         return sourceFiles;
120     }
121 
join(List<String> list, String delimiter)122     private static String join(List<String> list, String delimiter) {
123         final StringBuilder builder = new StringBuilder();
124         for (String s : list) {
125             builder.append(s);
126             builder.append(delimiter);
127         }
128         // Adding the delimiter each time and then removing the last one at the end is more
129         // efficient than doing a check in each iteration of the loop.
130         return builder.substring(0, builder.length() - delimiter.length());
131     }
132 
main(String[] args)133     public static void main(String[] args) throws Exception {
134         final HashMap<String, String> argsMap = KeyValueArgsParser.parse(args);
135         final String sourcePath = argsMap.get("-s");
136         final String docletPath = argsMap.get("-d");
137         if (sourcePath == null || docletPath == null) {
138             usage(args);
139         }
140         System.exit(new JavaScanner(new File(sourcePath), new File(docletPath)).scan());
141     }
142 
usage(String[] args)143     private static void usage(String[] args) {
144         System.err.println("Arguments: " + Arrays.toString(args));
145         System.err.println("Usage: javascanner -s SOURCE_DIR -d DOCLET_PATH");
146         System.exit(1);
147     }
148 }
149