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 com.android.cts.xmlgenerator;
18 
19 import vogar.Expectation;
20 import vogar.ExpectationStore;
21 import vogar.Result;
22 
23 import com.android.compatibility.common.util.AbiUtils;
24 
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.io.PrintWriter;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Map;
34 import java.util.List;
35 import java.util.Set;
36 
37 /**
38  * Generator of TestPackage XML files for native tests.
39  *
40  * It takes in an input of the following form:
41  *
42  * suite: x.y.z
43  * case:TestClass1
44  * test:testMethod1
45  * test:testMethod2
46  * case:TestClass2
47  * test:testMethod1
48  * suite: x.y
49  * case:TestClass3
50  * test:testMethod2
51  */
52 class XmlGenerator {
53 
54     /** Example: com.android.cts.holo */
55     private final String mAppNamespace;
56 
57     /** Test package name like "android.nativemedia" to group the tests. */
58     private final String mAppPackageName;
59 
60     /** Name of the native executable. */
61     private final String mName;
62 
63     /** Test runner */
64     private final String mRunner;
65 
66     private final String mTargetBinaryName;
67 
68     private final String mTargetNameSpace;
69 
70     private final String mJarPath;
71 
72     private final String mTestType;
73 
74     /** Path to output file or null to just dump to standard out. */
75     private final String mOutputPath;
76 
77     /** ExpectationStore to filter out known failures. */
78     private final ExpectationStore mKnownFailures;
79 
80     /** ExpectationStore to filter out unsupported abis. */
81     private final ExpectationStore mUnsupportedAbis;
82 
83     private final String mArchitecture;
84 
85     private final Map<String, String> mAdditionalAttributes;
86 
XmlGenerator(ExpectationStore knownFailures, ExpectationStore unsupportedAbis, String architecture, String appNameSpace, String appPackageName, String name, String runner, String targetBinaryName, String targetNameSpace, String jarPath, String testType, String outputPath, Map<String, String> additionalAttributes)87     XmlGenerator(ExpectationStore knownFailures, ExpectationStore unsupportedAbis,
88             String architecture, String appNameSpace, String appPackageName, String name,
89             String runner, String targetBinaryName, String targetNameSpace, String jarPath,
90             String testType, String outputPath, Map<String, String> additionalAttributes) {
91         mAppNamespace = appNameSpace;
92         mAppPackageName = appPackageName;
93         mName = name;
94         mRunner = runner;
95         mTargetBinaryName = targetBinaryName;
96         mTargetNameSpace = targetNameSpace;
97         mJarPath = jarPath;
98         mTestType = testType;
99         mOutputPath = outputPath;
100         mKnownFailures = knownFailures;
101         mUnsupportedAbis = unsupportedAbis;
102         mArchitecture = architecture;
103         mAdditionalAttributes = additionalAttributes;
104     }
105 
writePackageXml()106     public void writePackageXml() throws IOException {
107         OutputStream output = System.out;
108         if (mOutputPath != null) {
109             File outputFile = new File(mOutputPath);
110             output = new FileOutputStream(outputFile);
111         }
112 
113         PrintWriter writer = null;
114         try {
115             writer = new PrintWriter(output);
116             writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
117             writeTestPackage(writer);
118         } finally {
119             if (writer != null) {
120                 writer.close();
121             }
122         }
123     }
124 
writeTestPackage(PrintWriter writer)125     private void writeTestPackage(PrintWriter writer) {
126         writer.append("<TestPackage");
127         if (mAppNamespace != null) {
128             writer.append(" appNameSpace=\"").append(mAppNamespace).append("\"");
129         }
130 
131         writer.append(" appPackageName=\"").append(mAppPackageName).append("\"");
132         writer.append(" name=\"").append(mName).append("\"");
133 
134         if (mRunner != null) {
135             writer.append(" runner=\"").append(mRunner).append("\"");
136         }
137 
138         if (mAppNamespace != null && mTargetNameSpace != null
139                 && !mAppNamespace.equals(mTargetNameSpace)) {
140             writer.append(" targetBinaryName=\"").append(mTargetBinaryName).append("\"");
141             writer.append(" targetNameSpace=\"").append(mTargetNameSpace).append("\"");
142         }
143 
144         if (mTestType != null && !mTestType.isEmpty()) {
145             writer.append(" testType=\"").append(mTestType).append("\"");
146         }
147 
148         if (mJarPath != null) {
149             writer.append(" jarPath=\"").append(mJarPath).append("\"");
150         }
151 
152         for (Map.Entry<String, String> entry : mAdditionalAttributes.entrySet()) {
153             writer.append(String.format(" %s=\"%s\"", entry.getKey(), entry.getValue()));
154         }
155 
156         writer.println(" version=\"1.0\">");
157 
158         TestListParser parser = new TestListParser();
159         Collection<TestSuite> suites = parser.parse(System.in);
160         StringBuilder nameCollector = new StringBuilder();
161         writeTestSuites(writer, suites, nameCollector);
162         writer.println("</TestPackage>");
163     }
164 
writeTestSuites(PrintWriter writer, Collection<TestSuite> suites, StringBuilder nameCollector)165     private void writeTestSuites(PrintWriter writer, Collection<TestSuite> suites,
166             StringBuilder nameCollector) {
167         Collection<TestSuite> sorted = sortCollection(suites);
168         for (TestSuite suite : sorted) {
169             if (suite.countTests() == 0) {
170                 continue;
171             }
172             writer.append("<TestSuite name=\"").append(suite.getName()).println("\">");
173 
174             String namePart = suite.getName();
175             if (nameCollector.length() > 0) {
176                 namePart = "." + namePart;
177             }
178             nameCollector.append(namePart);
179 
180             writeTestSuites(writer, suite.getSuites(), nameCollector);
181             writeTestCases(writer, suite.getCases(), nameCollector);
182 
183             nameCollector.delete(nameCollector.length() - namePart.length(),
184                     nameCollector.length());
185             writer.println("</TestSuite>");
186         }
187     }
188 
writeTestCases(PrintWriter writer, Collection<TestCase> cases, StringBuilder nameCollector)189     private void writeTestCases(PrintWriter writer, Collection<TestCase> cases,
190             StringBuilder nameCollector) {
191         Collection<TestCase> sorted = sortCollection(cases);
192         for (TestCase testCase : sorted) {
193             if (testCase.countTests() == 0) {
194                 continue;
195             }
196             String name = testCase.getName();
197             writer.append("<TestCase name=\"").append(name).println("\">");
198             nameCollector.append('.').append(name);
199 
200             writeTests(writer, testCase.getTests(), nameCollector);
201 
202             nameCollector.delete(nameCollector.length() - name.length() - 1,
203                     nameCollector.length());
204             writer.println("</TestCase>");
205         }
206     }
207 
writeTests(PrintWriter writer, Collection<Test> tests, StringBuilder nameCollector)208     private void writeTests(PrintWriter writer, Collection<Test> tests,
209             StringBuilder nameCollector) {
210         Collection<Test> sorted = sortCollection(tests);
211         for (Test test : sorted) {
212             String className = nameCollector.toString();
213             nameCollector.append('#').append(test.getName());
214             writer.append("<Test name=\"").append(test.getName()).append("\"");
215             String abis = getSupportedAbis(mUnsupportedAbis, mArchitecture,
216                     className, nameCollector.toString()).toString();
217             writer.append(" abis=\"" + abis.substring(1, abis.length() - 1) + "\"");
218             if (isKnownFailure(mKnownFailures, nameCollector.toString())) {
219                 writer.append(" expectation=\"failure\"");
220             }
221             if (test.getTimeout() >= 0) {
222                 writer.append(" timeout=\"" + test.getTimeout() + "\"");
223             }
224             writer.println(" />");
225 
226             nameCollector.delete(nameCollector.length() - test.getName().length() - 1,
227                     nameCollector.length());
228         }
229     }
230 
sortCollection(Collection<E> col)231     private <E extends Comparable<E>> Collection<E> sortCollection(Collection<E> col) {
232         List<E> list = new ArrayList<E>(col);
233         Collections.sort(list);
234         return list;
235     }
236 
isKnownFailure(ExpectationStore expectationStore, String testName)237     public static boolean isKnownFailure(ExpectationStore expectationStore, String testName) {
238         return expectationStore != null
239             && expectationStore.get(testName).getResult() != Result.SUCCESS;
240     }
241 
242     // Returns the list of ABIs supported by this TestCase on this architecture.
getSupportedAbis(ExpectationStore expectationStore, String architecture, String className, String testName)243     public static Set<String> getSupportedAbis(ExpectationStore expectationStore,
244             String architecture, String className, String testName) {
245         Set<String> supportedAbis = AbiUtils.getAbisForArch(architecture);
246         if (expectationStore == null) {
247             return supportedAbis;
248         }
249 
250         removeUnsupportedAbis(expectationStore.get(className), supportedAbis);
251         removeUnsupportedAbis(expectationStore.get(testName), supportedAbis);
252         return supportedAbis;
253     }
254 
removeUnsupportedAbis(Expectation expectation, Set<String> supportedAbis)255     public static void removeUnsupportedAbis(Expectation expectation, Set<String> supportedAbis) {
256         if (expectation == null) {
257             return;
258         }
259 
260         String description = expectation.getDescription();
261         if (description.isEmpty()) {
262             return;
263         }
264 
265         String[] unsupportedAbis = description.split(":")[1].split(",");
266         for (String a : unsupportedAbis) {
267             String abi = a.trim();
268             if (!AbiUtils.isAbiSupportedByCompatibility(abi)) {
269                 throw new RuntimeException(
270                         String.format("Unrecognised ABI %s in %s", abi, description));
271             }
272             supportedAbis.remove(abi);
273         }
274     }
275 
276 }
277