/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include <sys/types.h> #include <regex.h> #include <stdlib.h> #include <stdio.h> #include "Log.h" #include "audio/RemoteAudio.h" #include "ClientImpl.h" #include "Report.h" #include "Settings.h" #include "StringUtil.h" #include "task/TaskCase.h" static const android::String8 STR_NAME("name"); static const android::String8 STR_VERSION("version"); static const android::String8 STR_DESCRIPTION("description"); TaskCase::TaskCase() : TaskGeneric(TaskGeneric::ETaskCase), mClient(NULL) { const android::String8* list[] = {&STR_NAME, &STR_VERSION, &STR_DESCRIPTION, NULL}; registerSupportedStringAttributes(list); } TaskCase::~TaskCase() { delete mClient; } bool TaskCase::getCaseName(android::String8& name) const { if (!findStringAttribute(STR_NAME, name)) { LOGW("TaskCase no name"); return false; } return true; } bool TaskCase::addChild(TaskGeneric* child) { if ((child->getType() != TaskGeneric::ETaskSetup) && (child->getType() != TaskGeneric::ETaskAction) && (child->getType() != TaskGeneric::ETaskSave)) { LOGE("TestCase::addChild wrong child type %d", child->getType()); return false; } return TaskGeneric::addChild(child); } template <typename T> bool registerGeneric( typename std::map<android::String8, T>& map, const android::String8& name, T& data) { typename std::map<android::String8, T>::iterator it; it = map.find(name); if (it != map.end()) { LOGV("registerGeneric key %s already registered", name.string()); return false; } LOGD("registerGeneric registered key %s", name.string()); map[name] = data; return true; } template <typename T> bool findGeneric(typename std::map<android::String8, T>& map, const android::String8& name, T& data) { LOGD("findGeneric key %s", name.string()); typename std::map<android::String8, T>::iterator it; it = map.find(name); if (it == map.end()) { return false; } data = it->second; return true; } template <typename T> bool updateGeneric(typename std::map<android::String8, T>& map, const android::String8& name, T& data) { LOGD("updateGeneric key %s", name.string()); typename std::map<android::String8, T>::iterator it; it = map.find(name); if (it == map.end()) { return false; } it->second = data; return true; } // return all the matches for the given regular expression. // name string and the data itself is copied. template <typename T> typename std::list<std::pair<android::String8, T> >* findAllGeneric( typename std::map<android::String8, T>& map, const char* re) { regex_t regex; if (regcomp(®ex, re, REG_EXTENDED | REG_NOSUB) != 0) { LOGE("regcomp failed"); return NULL; } typename std::map<android::String8, T>::iterator it; typename std::list<std::pair<android::String8, T> >* list = NULL; for (it = map.begin(); it != map.end(); it++) { if (regexec(®ex, it->first, 0, NULL, 0) == 0) { if (list == NULL) { // create only when found list = new std::list<std::pair<android::String8, T> >(); if (list == NULL) { regfree(®ex); return NULL; } } typename std::pair<android::String8, T> match(it->first, it->second); list->push_back(match); } } regfree(®ex); return list; } bool TaskCase::registerBuffer(const android::String8& orig, android::sp<Buffer>& buffer) { android::String8 translated; if (!translateVarName(orig, translated)) { return false; } return registerGeneric<android::sp<Buffer> >(mBufferList, translated, buffer); } bool TaskCase::updateBuffer(const android::String8& orig, android::sp<Buffer>& buffer) { android::String8 translated; if (!translateVarName(orig, translated)) { return false; } return updateGeneric<android::sp<Buffer> >(mBufferList, translated, buffer); } android::sp<Buffer> TaskCase::findBuffer(const android::String8& orig) { android::String8 translated; android::sp<Buffer> result; if (!translateVarName(orig, translated)) { return result; } findGeneric<android::sp<Buffer> >(mBufferList, translated, result); return result; } std::list<TaskCase::BufferPair>* TaskCase::findAllBuffers(const android::String8& re) { android::String8 translated; if (!translateVarName(re, translated)) { return NULL; } return findAllGeneric<android::sp<Buffer> >(mBufferList, translated.string()); } bool TaskCase::registerValue(const android::String8& orig, Value& val) { android::String8 translated; if (!translateVarName(orig, translated)) { return false; } LOGD("str %x", translated.string()); return registerGeneric<Value>(mValueList, translated, val); } bool TaskCase::updateValue(const android::String8& orig, Value& val) { android::String8 translated; if (!translateVarName(orig, translated)) { return false; } return updateGeneric<Value>(mValueList, translated, val); } bool TaskCase::findValue(const android::String8& orig, Value& val) { android::String8 translated; if (!translateVarName(orig, translated)) { return false; } return findGeneric<Value>(mValueList, translated, val); } std::list<TaskCase::ValuePair>* TaskCase::findAllValues(const android::String8& re) { android::String8 translated; if (!translateVarName(re, translated)) { return NULL; } return findAllGeneric<Value>(mValueList, translated.string()); } bool TaskCase::registerIndex(const android::String8& name, int value) { return registerGeneric<int>(mIndexList, name, value); } bool TaskCase::updateIndex(const android::String8& name, int value) { return updateGeneric<int>(mIndexList, name, value); } bool TaskCase::findIndex(const android::String8& name, int& val) { return findGeneric<int>(mIndexList, name, val); } std::list<TaskCase::IndexPair>* TaskCase::findAllIndices(const android::String8& re) { android::String8 translated; if (!translateVarName(re, translated)) { return NULL; } return findAllGeneric<int>(mIndexList, translated.string()); } bool TaskCase::translateVarName(const android::String8& orig, android::String8& translated) { const char* src = orig.string(); const int nmatch = 2; regmatch_t pmatch[nmatch]; regex_t re; size_t strStart = 0; if (regcomp(&re, "[a-z0-9_]*[$]([a-z0-9]+)[_]*", REG_EXTENDED) != 0) { LOGE("regcomp failed"); return false; } bool result = false; size_t matchStart = 0; size_t matchEnd = 0; while (regexec(&re, src, nmatch, pmatch, 0) == 0) { matchStart = strStart + pmatch[1].rm_so; matchEnd = strStart + pmatch[1].rm_eo; translated.append(StringUtil::substr(orig, strStart, pmatch[1].rm_so - 1)); //-1 for $ android::String8 indexName; indexName.append(StringUtil::substr(orig, matchStart, matchEnd - matchStart)); int val; if (!findIndex(indexName, val)) { LOGE("TaskCase::translateVarName no index with name %s", indexName.string()); regfree(&re); return false; } translated.appendFormat("%d", val); LOGD("match found strStart %d, matchStart %d, matchEnd %d, converted str %s", strStart, matchStart, matchEnd, translated.string()); src += pmatch[1].rm_eo; strStart += pmatch[1].rm_eo; } if (matchEnd < orig.length()) { //LOGD("%d %d", matchEnd, orig.length()); translated.append(StringUtil::substr(orig, matchEnd, orig.length() - matchEnd)); } LOGD("translated str %s to %s", orig.string(), translated.string()); regfree(&re); return true; } android::sp<RemoteAudio>& TaskCase::getRemoteAudio() { if (mClient == NULL) { mClient = new ClientImpl(); ASSERT(mClient->init(Settings::Instance()->getSetting(Settings::EADB))); } return mClient->getAudio(); } void TaskCase::releaseRemoteAudio() { delete mClient; mClient = NULL; } void TaskCase::setDetails(android::String8 details) { mDetails = details; } const android::String8& TaskCase::getDetails() const { return mDetails; } TaskGeneric::ExecutionResult TaskCase::run() { android::String8 name; android::String8 version; //LOGI("str %d, %d", strlen(STR_NAME), strlen(STR_VERSION)); if (!findStringAttribute(STR_NAME, name) || !findStringAttribute(STR_VERSION, version)) { LOGW("TaskCase::run no name or version information"); } MSG("== Test case %s version %s started ==", name.string(), version.string()); std::list<TaskGeneric*>::iterator i = getChildren().begin(); std::list<TaskGeneric*>::iterator end = getChildren().end(); TaskGeneric* setup = *i; i++; TaskGeneric* action = *i; i++; TaskGeneric* save = (i == end)? NULL : *i; if (save == NULL) { LOGW("No save stage in test case"); } bool testPassed = true; TaskGeneric::ExecutionResult result = setup->run(); TaskGeneric::ExecutionResult resultAction(TaskGeneric::EResultOK); if (result != TaskGeneric::EResultOK) { MSG("== setup stage failed %d ==", result); testPassed = false; } else { resultAction = action->run(); if (resultAction != TaskGeneric::EResultPass) { MSG("== action stage failed %d ==", resultAction); testPassed = false; } // save done even for failure if possible if (save != NULL) { result = save->run(); } if (result != TaskGeneric::EResultOK) { MSG("== save stage failed %d ==", result); testPassed = false; } } if (testPassed) { result = TaskGeneric::EResultPass; MSG("== Case %s Passed ==", name.string()); Report::Instance()->addCasePassed(this); } else { if (resultAction != TaskGeneric::EResultOK) { result = resultAction; } MSG("== Case %s Failed ==", name.string()); Report::Instance()->addCaseFailed(this); } // release remote audio for other cases to use releaseRemoteAudio(); return result; }