• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 util.build;
18 
19 import java.io.File;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.List;
26 import java.util.Set;
27 import java.util.TreeSet;
28 
29 /**
30  * Main class to generate data from the test suite to later run from a shell
31  * script. the project's home folder.<br>
32  * <project-home>/src must contain the java sources<br>
33  * <project-home>/src/<for-each-package>/Main_testN1.java will be generated<br>
34  * (one Main class for each test method in the Test_... class
35  */
36 public class BuildDalvikSuite extends BuildUtilBase {
37 
38     public static final String TARGET_MAIN_FILE = "mains.jar";
39 
40     // the folder for the generated junit-files for the cts host (which in turn
41     // execute the real vm tests using adb push/shell etc)
42     private String OUTPUT_FOLDER = "";
43     private String COMPILED_CLASSES_FOLDER = "";
44 
45     private String JAVASRC_FOLDER;
46 
47     /**
48      * @param args
49      *            args 0 must be the project root folder (where src, lib etc.
50      *            resides)
51      * @throws IOException
52      */
main(String[] args)53     public static void main(String[] args) throws IOException {
54         BuildDalvikSuite cat = new BuildDalvikSuite();
55         if (!cat.parseArgs(args)) {
56           printUsage();
57           System.exit(-1);
58         }
59 
60         long start = System.currentTimeMillis();
61         cat.run(null);
62         long end = System.currentTimeMillis();
63 
64         System.out.println("elapsed seconds: " + (end - start) / 1000);
65     }
66 
parseArgs(String[] args)67     private boolean parseArgs(String[] args) {
68       if (args.length == 3) {
69           JAVASRC_FOLDER = args[0];
70           OUTPUT_FOLDER = args[1];
71           COMPILED_CLASSES_FOLDER = args[2];
72           return true;
73       } else {
74           return false;
75       }
76     }
77 
printUsage()78     private static void printUsage() {
79         System.out.println("usage: $(JAVA) -cp $(CLASSPATH) util.build.BuildDalvikSuite" +
80                 " JAVASRC_FOLDER OUTPUT_FOLDER COMPILED_CLASSES_FOLDER");
81     }
82 
83     class MyTestHandler implements TestHandler {
84         public String datafileContent = "";
85         Set<BuildStep> targets = new TreeSet<BuildStep>();
86 
87         @Override
handleTest(String fqcn, List<String> methods)88         public void handleTest(String fqcn, List<String> methods) {
89             int lastDotPos = fqcn.lastIndexOf('.');
90             String pName = fqcn.substring(0, lastDotPos);
91             String classOnlyName = fqcn.substring(lastDotPos + 1);
92 
93             Collections.sort(methods, new Comparator<String>() {
94                 @Override
95                 public int compare(String s1, String s2) {
96                     // TODO sort according: test ... N, B, E, VFE
97                     return s1.compareTo(s2);
98                 }
99             });
100             for (String method : methods) {
101                 // e.g. testN1
102                 if (!method.startsWith("test")) {
103                     throw new RuntimeException("no test method: " + method);
104                 }
105 
106                 // generate the Main_xx java class
107 
108                 // a Main_testXXX.java contains:
109                 // package <packagenamehere>;
110                 // public class Main_testxxx {
111                 // public static void main(String[] args) {
112                 // new dxc.junit.opcodes.aaload.Test_aaload().testN1();
113                 // }
114                 // }
115                 MethodData md = parseTestMethod(pName, classOnlyName, method);
116                 String methodContent = md.methodBody;
117 
118                 List<String> dependentTestClassNames = parseTestClassName(pName,
119                         classOnlyName, methodContent);
120 
121                 if (dependentTestClassNames.isEmpty()) {
122                     continue;
123                 }
124 
125                 // prepare the entry in the data file for the bash script.
126                 // e.g.
127                 // main class to execute; opcode/constraint; test purpose
128                 // dxc.junit.opcodes.aaload.Main_testN1;aaload;normal case test
129                 // (#1)
130 
131                 char ca = method.charAt("test".length()); // either N,B,E,
132                 // or V (VFE)
133                 String comment;
134                 switch (ca) {
135                 case 'N':
136                     comment = "Normal #" + method.substring(5);
137                     break;
138                 case 'B':
139                     comment = "Boundary #" + method.substring(5);
140                     break;
141                 case 'E':
142                     comment = "Exception #" + method.substring(5);
143                     break;
144                 case 'V':
145                     comment = "Verifier #" + method.substring(7);
146                     break;
147                 default:
148                     throw new RuntimeException("unknown test abbreviation:"
149                             + method + " for " + fqcn);
150                 }
151 
152                 String line = pName + ".Main_" + method + ";";
153                 for (String className : dependentTestClassNames) {
154                     line += className + " ";
155                 }
156 
157 
158                 // test description
159                 String[] pparts = pName.split("\\.");
160                 // detail e.g. add_double
161                 String detail = pparts[pparts.length-1];
162                 // type := opcode | verify
163                 String type = pparts[pparts.length-2];
164 
165                 String description;
166                 if ("format".equals(type)) {
167                     description = "format";
168                 } else if ("opcodes".equals(type)) {
169                     // Beautify name, so it matches the actual mnemonic
170                     detail = detail.replaceAll("_", "-");
171                     detail = detail.replace("-from16", "/from16");
172                     detail = detail.replace("-high16", "/high16");
173                     detail = detail.replace("-lit8", "/lit8");
174                     detail = detail.replace("-lit16", "/lit16");
175                     detail = detail.replace("-4", "/4");
176                     detail = detail.replace("-16", "/16");
177                     detail = detail.replace("-32", "/32");
178                     detail = detail.replace("-jumbo", "/jumbo");
179                     detail = detail.replace("-range", "/range");
180                     detail = detail.replace("-2addr", "/2addr");
181 
182                     // Unescape reserved words
183                     detail = detail.replace("opc-", "");
184 
185                     description = detail;
186                 } else if ("verify".equals(type)) {
187                     description = "verifier";
188                 } else {
189                     description = type + " " + detail;
190                 }
191 
192                 String details = (md.title != null ? md.title : "");
193                 if (md.constraint != null) {
194                     details = " Constraint " + md.constraint + ", " + details;
195                 }
196                 if (details.length() != 0) {
197                     details = details.substring(0, 1).toUpperCase()
198                             + details.substring(1);
199                 }
200 
201                 line += ";" + description + ";" + comment + ";" + details;
202 
203                 datafileContent += line + "\n";
204                 generateBuildStepFor(dependentTestClassNames, targets);
205             }
206         }
207     }
208 
209     @Override
handleTests(JUnitTestCollector tests, TestHandler ignored)210     protected void handleTests(JUnitTestCollector tests, TestHandler ignored) {
211         MyTestHandler handler = new MyTestHandler();
212         super.handleTests(tests, handler);
213 
214         File scriptDataDir = new File(OUTPUT_FOLDER + "/data/");
215         scriptDataDir.mkdirs();
216         writeToFile(new File(scriptDataDir, "scriptdata"), handler.datafileContent);
217 
218         for (BuildStep buildStep : handler.targets) {
219             if (!buildStep.build()) {
220                 System.out.println("building failed. buildStep: " +
221                         buildStep.getClass().getName() + ", " + buildStep);
222                 System.exit(1);
223             }
224         }
225     }
226 
generateBuildStepFor(Collection<String> dependentTestClassNames, Set<BuildStep> targets)227     private void generateBuildStepFor(Collection<String> dependentTestClassNames,
228             Set<BuildStep> targets) {
229         for (String dependentTestClassName : dependentTestClassNames) {
230             generateBuildStepForDependant(dependentTestClassName, targets);
231         }
232     }
233 
generateBuildStepForDependant(String dependentTestClassName, Set<BuildStep> targets)234     private void generateBuildStepForDependant(String dependentTestClassName,
235             Set<BuildStep> targets) {
236 
237         File sourceFolder = new File(JAVASRC_FOLDER);
238         String fileName = dependentTestClassName.replace('.', '/').trim();
239 
240         if (new File(sourceFolder, fileName + ".dfh").exists()) {
241             // Handled in vmtests-dfh-dex-generated build rule.
242             return;
243         }
244 
245         if (new File(sourceFolder, fileName + ".d").exists()) {
246             // Handled in vmtests-dasm-dex-generated build rule.
247             return;
248         }
249 
250         {
251             // Build dex from a single '*.smali' file or a *.smalis' dir
252             // containing multiple smali files.
253             File dexFile = null;
254             SmaliBuildStep buildStep = null;
255             File smaliFile = new File(sourceFolder, fileName + ".smali");
256             File smalisDir = new File(sourceFolder, fileName + ".smalis");
257 
258             if (smaliFile.exists()) {
259                 dexFile = new File(OUTPUT_FOLDER, fileName + ".dex");
260                 buildStep = new SmaliBuildStep(
261                     Collections.singletonList(smaliFile.getAbsolutePath()), dexFile);
262             } else if (smalisDir.exists() && smalisDir.isDirectory()) {
263                 List<String> inputFiles = new ArrayList<>();
264                 for (File f: smalisDir.listFiles()) {
265                     inputFiles.add(f.getAbsolutePath());
266                 }
267                 dexFile = new File(OUTPUT_FOLDER, fileName + ".dex");
268                 buildStep = new SmaliBuildStep(inputFiles, dexFile);
269             }
270 
271             if (buildStep != null) {
272                 BuildStep.BuildFile jarFile = new BuildStep.BuildFile(
273                         OUTPUT_FOLDER, fileName + ".jar");
274                 JarBuildStep jarBuildStep = new JarBuildStep(new BuildStep.BuildFile(dexFile),
275                         "classes.dex", jarFile, true);
276                 jarBuildStep.addChild(buildStep);
277                 targets.add(jarBuildStep);
278                 return;
279             }
280         }
281 
282         File srcFile = new File(sourceFolder, fileName + ".java");
283         if (srcFile.exists()) {
284             BuildStep dexBuildStep;
285             dexBuildStep = generateDexBuildStep(
286               COMPILED_CLASSES_FOLDER, fileName);
287             targets.add(dexBuildStep);
288             return;
289         }
290 
291         try {
292             if (Class.forName(dependentTestClassName) != null) {
293                 BuildStep dexBuildStep = generateDexBuildStep(
294                     COMPILED_CLASSES_FOLDER, fileName);
295                 targets.add(dexBuildStep);
296                 return;
297             }
298         } catch (ClassNotFoundException e) {
299             // do nothing
300         }
301 
302         throw new RuntimeException("neither .dfh,.d,.java file of dependant test class found : " +
303                 dependentTestClassName + ";" + fileName);
304     }
305 
generateDexBuildStep(String classFileFolder, String classFileName)306     private BuildStep generateDexBuildStep(String classFileFolder,
307             String classFileName) {
308         BuildStep.BuildFile classFile = new BuildStep.BuildFile(
309                 classFileFolder, classFileName + ".class");
310 
311         BuildStep.BuildFile tmpJarFile = new BuildStep.BuildFile(
312                 OUTPUT_FOLDER,
313                 classFileName + "_tmp.jar");
314 
315         JarBuildStep jarBuildStep = new JarBuildStep(classFile,
316                 classFileName + ".class", tmpJarFile, false);
317 
318         BuildStep.BuildFile outputFile = new BuildStep.BuildFile(
319                 OUTPUT_FOLDER,
320                 classFileName + ".jar");
321 
322         D8BuildStep dexBuildStep = new D8BuildStep(tmpJarFile,
323                 outputFile,
324                 true);
325 
326         dexBuildStep.addChild(jarBuildStep);
327         return dexBuildStep;
328     }
329 }
330