1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 #include <sys/types.h> 18 #include <regex.h> 19 #include <stdlib.h> 20 #include <stdio.h> 21 22 #include "Log.h" 23 #include "audio/RemoteAudio.h" 24 #include "ClientImpl.h" 25 #include "Report.h" 26 #include "Settings.h" 27 #include "StringUtil.h" 28 #include "task/TaskCase.h" 29 30 static const android::String8 STR_NAME("name"); 31 static const android::String8 STR_VERSION("version"); 32 static const android::String8 STR_DESCRIPTION("description"); 33 34 TaskCase::TaskCase() 35 : TaskGeneric(TaskGeneric::ETaskCase), 36 mClient(NULL) 37 { 38 const android::String8* list[] = {&STR_NAME, &STR_VERSION, &STR_DESCRIPTION, NULL}; 39 registerSupportedStringAttributes(list); 40 } 41 42 TaskCase::~TaskCase() 43 { 44 delete mClient; 45 } 46 47 bool TaskCase::getCaseName(android::String8& name) const 48 { 49 if (!findStringAttribute(STR_NAME, name)) { 50 LOGW("TaskCase no name"); 51 return false; 52 } 53 return true; 54 } 55 56 bool TaskCase::addChild(TaskGeneric* child) 57 { 58 if ((child->getType() != TaskGeneric::ETaskSetup) 59 && (child->getType() != TaskGeneric::ETaskAction) 60 && (child->getType() != TaskGeneric::ETaskSave)) { 61 LOGE("TestCase::addChild wrong child type %d", child->getType()); 62 return false; 63 } 64 return TaskGeneric::addChild(child); 65 } 66 67 template <typename T> bool registerGeneric( 68 typename std::map<android::String8, T>& map, 69 const android::String8& name, T& data) 70 { 71 typename std::map<android::String8, T>::iterator it; 72 it = map.find(name); 73 if (it != map.end()) { 74 LOGV("registerGeneric key %s already registered", name.string()); 75 return false; 76 } 77 LOGD("registerGeneric registered key %s", name.string()); 78 map[name] = data; 79 return true; 80 } 81 82 template <typename T> bool findGeneric(typename std::map<android::String8, T>& map, 83 const android::String8& name, T& data) 84 { 85 LOGD("findGeneric key %s", name.string()); 86 typename std::map<android::String8, T>::iterator it; 87 it = map.find(name); 88 if (it == map.end()) { 89 return false; 90 } 91 data = it->second; 92 return true; 93 } 94 95 template <typename T> bool updateGeneric(typename std::map<android::String8, T>& map, 96 const android::String8& name, T& data) 97 { 98 LOGD("updateGeneric key %s", name.string()); 99 typename std::map<android::String8, T>::iterator it; 100 it = map.find(name); 101 if (it == map.end()) { 102 return false; 103 } 104 it->second = data; 105 return true; 106 } 107 108 // return all the matches for the given regular expression. 109 // name string and the data itself is copied. 110 template <typename T> typename std::list<std::pair<android::String8, T> >* findAllGeneric( 111 typename std::map<android::String8, T>& map, const char* re) 112 { 113 regex_t regex; 114 if (regcomp(®ex, re, REG_EXTENDED | REG_NOSUB) != 0) { 115 LOGE("regcomp failed"); 116 return NULL; 117 } 118 typename std::map<android::String8, T>::iterator it; 119 typename std::list<std::pair<android::String8, T> >* list = NULL; 120 for (it = map.begin(); it != map.end(); it++) { 121 if (regexec(®ex, it->first, 0, NULL, 0) == 0) { 122 if (list == NULL) { // create only when found 123 list = new std::list<std::pair<android::String8, T> >(); 124 if (list == NULL) { 125 regfree(®ex); 126 return NULL; 127 } 128 } 129 typename std::pair<android::String8, T> match(it->first, it->second); 130 list->push_back(match); 131 } 132 } 133 regfree(®ex); 134 return list; 135 } 136 137 138 bool TaskCase::registerBuffer(const android::String8& orig, android::sp<Buffer>& buffer) 139 { 140 android::String8 translated; 141 if (!translateVarName(orig, translated)) { 142 return false; 143 } 144 return registerGeneric<android::sp<Buffer> >(mBufferList, translated, buffer); 145 } 146 147 bool TaskCase::updateBuffer(const android::String8& orig, android::sp<Buffer>& buffer) 148 { 149 android::String8 translated; 150 if (!translateVarName(orig, translated)) { 151 return false; 152 } 153 return updateGeneric<android::sp<Buffer> >(mBufferList, translated, buffer); 154 } 155 156 android::sp<Buffer> TaskCase::findBuffer(const android::String8& orig) 157 { 158 android::String8 translated; 159 android::sp<Buffer> result; 160 if (!translateVarName(orig, translated)) { 161 return result; 162 } 163 findGeneric<android::sp<Buffer> >(mBufferList, translated, result); 164 return result; 165 } 166 167 std::list<TaskCase::BufferPair>* TaskCase::findAllBuffers(const android::String8& re) 168 { 169 android::String8 translated; 170 if (!translateVarName(re, translated)) { 171 return NULL; 172 } 173 return findAllGeneric<android::sp<Buffer> >(mBufferList, translated.string()); 174 } 175 176 177 bool TaskCase::registerValue(const android::String8& orig, Value& val) 178 { 179 android::String8 translated; 180 if (!translateVarName(orig, translated)) { 181 return false; 182 } 183 LOGD("str %x", translated.string()); 184 return registerGeneric<Value>(mValueList, translated, val); 185 } 186 187 bool TaskCase::updateValue(const android::String8& orig, Value& val) 188 { 189 android::String8 translated; 190 if (!translateVarName(orig, translated)) { 191 return false; 192 } 193 return updateGeneric<Value>(mValueList, translated, val); 194 } 195 196 bool TaskCase::findValue(const android::String8& orig, Value& val) 197 { 198 android::String8 translated; 199 if (!translateVarName(orig, translated)) { 200 return false; 201 } 202 return findGeneric<Value>(mValueList, translated, val); 203 } 204 205 std::list<TaskCase::ValuePair>* TaskCase::findAllValues(const android::String8& re) 206 { 207 android::String8 translated; 208 if (!translateVarName(re, translated)) { 209 return NULL; 210 } 211 return findAllGeneric<Value>(mValueList, translated.string()); 212 } 213 214 bool TaskCase::registerIndex(const android::String8& name, int value) 215 { 216 return registerGeneric<int>(mIndexList, name, value); 217 } 218 219 bool TaskCase::updateIndex(const android::String8& name, int value) 220 { 221 return updateGeneric<int>(mIndexList, name, value); 222 } 223 224 bool TaskCase::findIndex(const android::String8& name, int& val) 225 { 226 return findGeneric<int>(mIndexList, name, val); 227 } 228 229 std::list<TaskCase::IndexPair>* TaskCase::findAllIndices(const android::String8& re) 230 { 231 android::String8 translated; 232 if (!translateVarName(re, translated)) { 233 return NULL; 234 } 235 return findAllGeneric<int>(mIndexList, translated.string()); 236 } 237 238 bool TaskCase::translateVarName(const android::String8& orig, android::String8& translated) 239 { 240 const char* src = orig.string(); 241 const int nmatch = 2; 242 regmatch_t pmatch[nmatch]; 243 regex_t re; 244 size_t strStart = 0; 245 246 if (regcomp(&re, "[a-z0-9_]*[$]([a-z0-9]+)[_]*", REG_EXTENDED) != 0) { 247 LOGE("regcomp failed"); 248 return false; 249 } 250 bool result = false; 251 size_t matchStart = 0; 252 size_t matchEnd = 0; 253 while (regexec(&re, src, nmatch, pmatch, 0) == 0) { 254 matchStart = strStart + pmatch[1].rm_so; 255 matchEnd = strStart + pmatch[1].rm_eo; 256 translated.append(StringUtil::substr(orig, strStart, pmatch[1].rm_so - 1)); //-1 for $ 257 android::String8 indexName; 258 indexName.append(StringUtil::substr(orig, matchStart, matchEnd - matchStart)); 259 int val; 260 if (!findIndex(indexName, val)) { 261 LOGE("TaskCase::translateVarName no index with name %s", indexName.string()); 262 regfree(&re); 263 return false; 264 } 265 translated.appendFormat("%d", val); 266 LOGD("match found strStart %d, matchStart %d, matchEnd %d, converted str %s", 267 strStart, matchStart, matchEnd, translated.string()); 268 src += pmatch[1].rm_eo; 269 strStart += pmatch[1].rm_eo; 270 } 271 if (matchEnd < orig.length()) { 272 //LOGD("%d %d", matchEnd, orig.length()); 273 translated.append(StringUtil::substr(orig, matchEnd, orig.length() - matchEnd)); 274 } 275 LOGD("translated str %s to %s", orig.string(), translated.string()); 276 regfree(&re); 277 return true; 278 } 279 280 android::sp<RemoteAudio>& TaskCase::getRemoteAudio() 281 { 282 if (mClient == NULL) { 283 mClient = new ClientImpl(); 284 ASSERT(mClient->init(Settings::Instance()->getSetting(Settings::EADB))); 285 } 286 return mClient->getAudio(); 287 } 288 289 void TaskCase::releaseRemoteAudio() 290 { 291 delete mClient; 292 mClient = NULL; 293 } 294 295 void TaskCase::setDetails(android::String8 details) 296 { 297 mDetails = details; 298 } 299 300 const android::String8& TaskCase::getDetails() const 301 { 302 return mDetails; 303 } 304 305 306 TaskGeneric::ExecutionResult TaskCase::run() 307 { 308 android::String8 name; 309 android::String8 version; 310 //LOGI("str %d, %d", strlen(STR_NAME), strlen(STR_VERSION)); 311 if (!findStringAttribute(STR_NAME, name) || !findStringAttribute(STR_VERSION, version)) { 312 LOGW("TaskCase::run no name or version information"); 313 } 314 MSG("== Test case %s version %s started ==", name.string(), version.string()); 315 std::list<TaskGeneric*>::iterator i = getChildren().begin(); 316 std::list<TaskGeneric*>::iterator end = getChildren().end(); 317 TaskGeneric* setup = *i; 318 i++; 319 TaskGeneric* action = *i; 320 i++; 321 TaskGeneric* save = (i == end)? NULL : *i; 322 if (save == NULL) { 323 LOGW("No save stage in test case"); 324 } 325 bool testPassed = true; 326 TaskGeneric::ExecutionResult result = setup->run(); 327 TaskGeneric::ExecutionResult resultAction(TaskGeneric::EResultOK); 328 if (result != TaskGeneric::EResultOK) { 329 MSG("== setup stage failed %d ==", result); 330 testPassed = false; 331 } else { 332 resultAction = action->run(); 333 if (resultAction != TaskGeneric::EResultPass) { 334 MSG("== action stage failed %d ==", resultAction); 335 testPassed = false; 336 } 337 // save done even for failure if possible 338 if (save != NULL) { 339 result = save->run(); 340 } 341 if (result != TaskGeneric::EResultOK) { 342 MSG("== save stage failed %d ==", result); 343 testPassed = false; 344 } 345 } 346 if (testPassed) { 347 result = TaskGeneric::EResultPass; 348 MSG("== Case %s Passed ==", name.string()); 349 Report::Instance()->addCasePassed(this); 350 } else { 351 if (resultAction != TaskGeneric::EResultOK) { 352 result = resultAction; 353 } 354 MSG("== Case %s Failed ==", name.string()); 355 Report::Instance()->addCaseFailed(this); 356 } 357 // release remote audio for other cases to use 358 releaseRemoteAudio(); 359 return result; 360 } 361 362