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