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 
TaskCase()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 
~TaskCase()42 TaskCase::~TaskCase()
43 {
44     delete mClient;
45 }
46 
getCaseName(android::String8 & name) const47 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 
addChild(TaskGeneric * child)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 
registerGeneric(typename std::map<android::String8,T> & map,const android::String8 & name,T & data)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 
findGeneric(typename std::map<android::String8,T> & map,const android::String8 & name,T & data)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 
updateGeneric(typename std::map<android::String8,T> & map,const android::String8 & name,T & data)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.
findAllGeneric(typename std::map<android::String8,T> & map,const char * re)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(&regex, 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(&regex, 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(&regex);
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(&regex);
134     return list;
135 }
136 
137 
registerBuffer(const android::String8 & orig,android::sp<Buffer> & buffer)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 
updateBuffer(const android::String8 & orig,android::sp<Buffer> & buffer)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 
findBuffer(const android::String8 & orig)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 
findAllBuffers(const android::String8 & re)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 
registerValue(const android::String8 & orig,Value & val)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 
updateValue(const android::String8 & orig,Value & val)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 
findValue(const android::String8 & orig,Value & val)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 
findAllValues(const android::String8 & re)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 
registerIndex(const android::String8 & name,int value)214 bool TaskCase::registerIndex(const android::String8& name, int value)
215 {
216     return registerGeneric<int>(mIndexList, name, value);
217 }
218 
updateIndex(const android::String8 & name,int value)219 bool TaskCase::updateIndex(const android::String8& name, int value)
220 {
221     return updateGeneric<int>(mIndexList, name, value);
222 }
223 
findIndex(const android::String8 & name,int & val)224 bool TaskCase::findIndex(const android::String8& name, int& val)
225 {
226     return findGeneric<int>(mIndexList, name, val);
227 }
228 
findAllIndices(const android::String8 & re)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 
translateVarName(const android::String8 & orig,android::String8 & translated)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 
getRemoteAudio()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 
releaseRemoteAudio()289 void TaskCase::releaseRemoteAudio()
290 {
291     delete mClient;
292     mClient = NULL;
293 }
294 
setDetails(android::String8 details)295 void TaskCase::setDetails(android::String8 details)
296 {
297     mDetails = details;
298 }
299 
getDetails() const300 const android::String8& TaskCase::getDetails() const
301 {
302     return mDetails;
303 }
304 
305 
run()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