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(®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
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