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 package com.android.cts.tradefed.result; 17 18 import com.android.ddmlib.testrunner.TestIdentifier; 19 import com.android.tradefed.result.TestResult; 20 21 import org.kxml2.io.KXmlSerializer; 22 import org.xmlpull.v1.XmlPullParser; 23 import org.xmlpull.v1.XmlPullParserException; 24 25 import java.io.IOException; 26 import java.util.Collection; 27 import java.util.Deque; 28 import java.util.LinkedHashMap; 29 import java.util.List; 30 import java.util.Map; 31 32 /** 33 * Data structure that represents a "TestSuite" XML element and its children. 34 */ 35 class TestSuite extends AbstractXmlPullParser { 36 37 static final String TAG = "TestSuite"; 38 39 private String mName; 40 41 // use linked hash map for predictable iteration order 42 Map<String, TestSuite> mChildSuiteMap = new LinkedHashMap<String, TestSuite>(); 43 Map<String, TestCase> mChildTestCaseMap = new LinkedHashMap<String, TestCase>(); 44 45 /** 46 * @param testSuite 47 */ TestSuite(String suiteName)48 public TestSuite(String suiteName) { 49 mName = suiteName; 50 } 51 TestSuite()52 public TestSuite() { 53 } 54 55 /** 56 * @return the name of this suite 57 */ getName()58 public String getName() { 59 return mName; 60 } 61 62 /** 63 * Set the name of this suite 64 */ setName(String name)65 public void setName(String name) { 66 mName = name; 67 } 68 69 /** 70 * Insert the given test result into this suite. 71 * 72 * @param suiteNames list of remaining suite names for this test 73 * @param testClassName the test class name 74 * @param testName the test method name 75 * @param testResult the {@link TestResult} 76 */ findTest(List<String> suiteNames, String testClassName, String testName, boolean insertIfMissing)77 public Test findTest(List<String> suiteNames, String testClassName, String testName, 78 boolean insertIfMissing) { 79 if (suiteNames.size() <= 0) { 80 // no more package segments 81 TestCase testCase = getTestCase(testClassName); 82 return testCase.findTest(testName, insertIfMissing); 83 } else { 84 String rootName = suiteNames.remove(0); 85 TestSuite suite = getTestSuite(rootName); 86 return suite.findTest(suiteNames, testClassName, testName, insertIfMissing); 87 } 88 } 89 90 /** 91 * Gets all the child {@link TestSuite}s 92 */ getTestSuites()93 public Collection<TestSuite> getTestSuites() { 94 return mChildSuiteMap.values(); 95 } 96 97 /** 98 * Gets all the child {@link TestCase}s 99 */ getTestCases()100 public Collection<TestCase> getTestCases() { 101 return mChildTestCaseMap.values(); 102 } 103 104 /** 105 * Get the child {@link TestSuite} with given name, creating if necessary. 106 * 107 * @param suiteName 108 * @return the {@link TestSuite} 109 */ getTestSuite(String suiteName)110 private TestSuite getTestSuite(String suiteName) { 111 TestSuite testSuite = mChildSuiteMap.get(suiteName); 112 if (testSuite == null) { 113 testSuite = new TestSuite(suiteName); 114 mChildSuiteMap.put(suiteName, testSuite); 115 } 116 return testSuite; 117 } 118 119 /** 120 * Get the child {@link TestCase} with given name, creating if necessary. 121 * @param testCaseName 122 * @return 123 */ getTestCase(String testCaseName)124 private TestCase getTestCase(String testCaseName) { 125 TestCase testCase = mChildTestCaseMap.get(testCaseName); 126 if (testCase == null) { 127 testCase = new TestCase(testCaseName); 128 mChildTestCaseMap.put(testCaseName, testCase); 129 } 130 return testCase; 131 } 132 133 /** 134 * Serialize this object and all its contents to XML. 135 * 136 * @param serializer 137 * @throws IOException 138 */ serialize(KXmlSerializer serializer)139 public void serialize(KXmlSerializer serializer) throws IOException { 140 if (mName != null) { 141 serializer.startTag(CtsXmlResultReporter.ns, TAG); 142 serializer.attribute(CtsXmlResultReporter.ns, "name", mName); 143 } 144 for (TestSuite childSuite : mChildSuiteMap.values()) { 145 childSuite.serialize(serializer); 146 } 147 for (TestCase childCase : mChildTestCaseMap.values()) { 148 childCase.serialize(serializer); 149 } 150 if (mName != null) { 151 serializer.endTag(CtsXmlResultReporter.ns, TAG); 152 } 153 } 154 155 /** 156 * Populates this class with suite result data parsed from XML. 157 * 158 * @param parser the {@link XmlPullParser}. Expected to be pointing at start 159 * of a TestSuite tag 160 */ 161 @Override parse(XmlPullParser parser)162 void parse(XmlPullParser parser) throws XmlPullParserException, IOException { 163 if (!parser.getName().equals(TAG)) { 164 throw new XmlPullParserException(String.format( 165 "invalid XML: Expected %s tag but received %s", TAG, parser.getName())); 166 } 167 setName(getAttribute(parser, "name")); 168 int eventType = parser.next(); 169 while (eventType != XmlPullParser.END_DOCUMENT) { 170 if (eventType == XmlPullParser.START_TAG && parser.getName().equals(TestSuite.TAG)) { 171 TestSuite suite = new TestSuite(); 172 suite.parse(parser); 173 insertSuite(suite); 174 } else if (eventType == XmlPullParser.START_TAG && parser.getName().equals( 175 TestCase.TAG)) { 176 TestCase testCase = new TestCase(); 177 testCase.parse(parser); 178 insertTestCase(testCase); 179 } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) { 180 return; 181 } 182 eventType = parser.next(); 183 } 184 } 185 186 /** 187 * Adds a child {@link TestCase}. 188 */ insertTestCase(TestCase testCase)189 public void insertTestCase(TestCase testCase) { 190 mChildTestCaseMap.put(testCase.getName(), testCase); 191 } 192 193 /** 194 * Adds a child {@link TestSuite}. 195 */ insertSuite(TestSuite suite)196 public void insertSuite(TestSuite suite) { 197 mChildSuiteMap.put(suite.getName(), suite); 198 } 199 200 201 /** 202 * Adds tests contained in this result that have the given <var>resultFilter</var> 203 * 204 * @param tests the {@link Collection} of {@link TestIdentifier}s to add to 205 * @param parentSuiteNames a {@link Deque} of parent suite names. Used to construct the full 206 * class name of the test 207 * @param resultFilter the {@link CtsTestStatus} to filter by 208 */ addTestsWithStatus(Collection<TestIdentifier> tests, Deque<String> parentSuiteNames, CtsTestStatus resultFilter)209 void addTestsWithStatus(Collection<TestIdentifier> tests, Deque<String> parentSuiteNames, 210 CtsTestStatus resultFilter) { 211 if (getName() != null) { 212 parentSuiteNames.addLast(getName()); 213 } 214 for (TestSuite suite : mChildSuiteMap.values()) { 215 suite.addTestsWithStatus(tests, parentSuiteNames, resultFilter); 216 } 217 for (TestCase testCase : mChildTestCaseMap.values()) { 218 testCase.addTestsWithStatus(tests, parentSuiteNames, resultFilter); 219 } 220 if (getName() != null) { 221 parentSuiteNames.removeLast(); 222 } 223 } 224 225 /** 226 * Count the number of tests in this {@link TestSuite} with given status. 227 * 228 * @param status 229 * @return the test count 230 */ countTests(CtsTestStatus status)231 public int countTests(CtsTestStatus status) { 232 int total = 0; 233 for (TestSuite suite : mChildSuiteMap.values()) { 234 total += suite.countTests(status); 235 } 236 for (TestCase testCase : mChildTestCaseMap.values()) { 237 total += testCase.countTests(status); 238 } 239 return total; 240 } 241 } 242