1 /* 2 * Copyright (C) 2010 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 package com.android.cts.tradefed.testtype; 17 18 import com.android.ddmlib.Log; 19 import com.android.ddmlib.testrunner.TestIdentifier; 20 import com.android.tradefed.util.xml.AbstractXmlParser; 21 22 import org.xml.sax.Attributes; 23 import org.xml.sax.helpers.DefaultHandler; 24 25 import java.util.Iterator; 26 import java.util.Stack; 27 28 /** 29 * Parser for CTS test case XML. 30 * <p/> 31 * Dumb parser that just retrieves data from in the test case xml and stuff it into a 32 * {@link TestPackageDef}. Currently performs limited error checking. 33 */ 34 public class TestPackageXmlParser extends AbstractXmlParser { 35 36 private static final String LOG_TAG = "TestPackageXmlParser"; 37 38 private final boolean mIncludeKnownFailures; 39 40 private TestPackageDef mPackageDef; 41 TestPackageXmlParser(boolean includeKnownFailures)42 public TestPackageXmlParser(boolean includeKnownFailures) { 43 mIncludeKnownFailures = includeKnownFailures; 44 } 45 46 /** 47 * SAX callback object. Handles parsing data from the xml tags. 48 * <p/> 49 * Expected structure: 50 * <TestPackage> 51 * <TestSuite ...> 52 * <TestCase> 53 * <Test> 54 */ 55 private class TestPackageHandler extends DefaultHandler { 56 57 private static final String TEST_PACKAGE_TAG = "TestPackage"; 58 private static final String TEST_SUITE_TAG = "TestSuite"; 59 private static final String TEST_CASE_TAG = "TestCase"; 60 private static final String TEST_TAG = "Test"; 61 62 // holds current class name segments 63 private Stack<String> mClassNameStack = new Stack<String>(); 64 65 @Override startElement(String uri, String localName, String name, Attributes attributes)66 public void startElement(String uri, String localName, String name, Attributes attributes) { 67 if (TEST_PACKAGE_TAG.equals(localName)) { 68 // appPackageName is used as the uri 69 final String entryUriValue = attributes.getValue("appPackageName"); 70 final String testPackageNameSpace = attributes.getValue("appNameSpace"); 71 final String packageName = attributes.getValue("name"); 72 final String runnerName = attributes.getValue("runner"); 73 final String jarPath = attributes.getValue("jarPath"); 74 final String signatureCheck = attributes.getValue("signatureCheck"); 75 final String javaPackageFilter = attributes.getValue("javaPackageFilter"); 76 final String targetBinaryName = attributes.getValue("targetBinaryName"); 77 final String targetNameSpace = attributes.getValue("targetNameSpace"); 78 79 mPackageDef = new TestPackageDef(); 80 mPackageDef.setUri(entryUriValue); 81 mPackageDef.setAppNameSpace(testPackageNameSpace); 82 mPackageDef.setName(packageName); 83 mPackageDef.setRunner(runnerName); 84 mPackageDef.setTestType(getTestType(attributes)); 85 mPackageDef.setJarPath(jarPath); 86 mPackageDef.setIsSignatureCheck(parseBoolean(signatureCheck)); 87 mPackageDef.setTestPackageName(javaPackageFilter); 88 mPackageDef.setTargetBinaryName(targetBinaryName); 89 mPackageDef.setTargetNameSpace(targetNameSpace); 90 91 // reset the class name 92 mClassNameStack = new Stack<String>(); 93 } else if (TEST_SUITE_TAG.equals(localName)) { 94 String packageSegment = attributes.getValue("name"); 95 if (packageSegment != null) { 96 mClassNameStack.push(packageSegment); 97 } else { 98 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 99 TEST_SUITE_TAG)); 100 } 101 } else if (TEST_CASE_TAG.equals(localName)) { 102 String classSegment = attributes.getValue("name"); 103 if (classSegment != null) { 104 mClassNameStack.push(classSegment); 105 } else { 106 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 107 TEST_CASE_TAG)); 108 } 109 } else if (TEST_TAG.equals(localName)) { 110 String methodName = attributes.getValue("name"); 111 if (mPackageDef == null) { 112 Log.e(LOG_TAG, String.format( 113 "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag", 114 TEST_TAG, TEST_PACKAGE_TAG)); 115 } else if (methodName == null) { 116 Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'", 117 TEST_TAG)); 118 } else { 119 // build class name from package segments 120 StringBuilder classNameBuilder = new StringBuilder(); 121 for (Iterator<String> iter = mClassNameStack.iterator(); iter.hasNext(); ) { 122 classNameBuilder.append(iter.next()); 123 if (iter.hasNext()) { 124 classNameBuilder.append("."); 125 } 126 } 127 128 TestIdentifier testId = new TestIdentifier(classNameBuilder.toString(), 129 methodName); 130 boolean isKnownFailure = "failure".equals(attributes.getValue("expectation")); 131 if (!isKnownFailure || mIncludeKnownFailures) { 132 mPackageDef.addTest(testId); 133 } 134 } 135 } 136 137 } 138 getTestType(Attributes attributes)139 private String getTestType(Attributes attributes) { 140 if (parseBoolean(attributes.getValue("hostSideOnly"))) { 141 return TestPackageDef.HOST_SIDE_ONLY_TEST; 142 } else if (parseBoolean(attributes.getValue("vmHostTest"))) { 143 return TestPackageDef.VM_HOST_TEST; 144 } else { 145 return attributes.getValue("testType"); 146 } 147 } 148 149 @Override endElement(String uri, String localName, String qName)150 public void endElement (String uri, String localName, String qName) { 151 if (TEST_SUITE_TAG.equals(localName) || TEST_CASE_TAG.equals(localName)) { 152 mClassNameStack.pop(); 153 } 154 } 155 156 /** 157 * Parse a boolean attribute value 158 */ parseBoolean(final String stringValue)159 private boolean parseBoolean(final String stringValue) { 160 return stringValue != null && 161 Boolean.parseBoolean(stringValue); 162 } 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override createXmlHandler()169 protected DefaultHandler createXmlHandler() { 170 return new TestPackageHandler(); 171 } 172 173 /** 174 * @returns the {@link TestPackageDef} containing data parsed from xml or <code>null</code> if 175 * xml did not contain the correct information. 176 */ getTestPackageDef()177 public TestPackageDef getTestPackageDef() { 178 return mPackageDef; 179 } 180 } 181