| /* MediaTek Inc. (C) 2016. All rights reserved. |
| * |
| * Copyright Statement: |
| * This software/firmware and related documentation ("MediaTek Software") are |
| * protected under relevant copyright laws. The information contained herein is |
| * confidential and proprietary to MediaTek Inc. and/or its licensors. Without |
| * the prior written permission of MediaTek inc. and/or its licensors, any |
| * reproduction, modification, use or disclosure of MediaTek Software, and |
| * information contained herein, in whole or in part, shall be strictly |
| * prohibited. |
| */ |
| |
| /* |
| * Description: |
| * Implement unit test cases |
| */ |
| |
| #include "AudioParamParserPriv.h" |
| |
| typedef APP_STATUS(*TEST_FUN)(AppHandle *appHandle); |
| |
| typedef struct { |
| AppHandle *appHandle; |
| int times; |
| TEST_FUN fun; |
| } ThreadParam; |
| |
| EXPORT APP_STATUS unitTest(AppHandle *appHandle) { |
| APP_STATUS res = APP_NO_ERROR; |
| APP_STATUS finalRes = APP_NO_ERROR; |
| |
| printf("===APP internal unit test===\n"); |
| #if 0 |
| res = testAppHandleInitUninit(); |
| if (res == APP_ERROR) { |
| finalRes = APP_ERROR; |
| } |
| printf("testAppHandleInitUninit: %s\n", res ? "pass" : "fail"); |
| #endif |
| res = testReadWriteParam(appHandle); |
| if (res == APP_ERROR) { |
| finalRes = APP_ERROR; |
| } |
| printf("testReadWriteParam: %s\n", res ? "pass" : "fail"); |
| |
| res = testMemoryLeak(appHandle); |
| if (res == APP_ERROR) { |
| finalRes = APP_ERROR; |
| } |
| printf("testMemoryLeak: %s\n", res ? "pass" : "fail"); |
| |
| res = testAudioTypeLock(appHandle); |
| if (res == APP_ERROR) { |
| finalRes = APP_ERROR; |
| } |
| printf("testAudioTypeLock: %s\n", res ? "pass" : "fail"); |
| printf("=============================\n"); |
| |
| return finalRes; |
| } |
| |
| |
| EXPORT void *commonThreadLoop(void *arg) { |
| ThreadParam threadParam = *(ThreadParam *)arg; |
| int i = 0 ; |
| for (i = 0; i < threadParam.times; i++) { |
| (*threadParam.fun)(threadParam.appHandle); |
| INFO_LOG("2nd thread round = %d\n", i); |
| } |
| return NULL; |
| } |
| |
| EXPORT void testDebugLevel() { |
| appSetDebugLevel(ERR_LEVEL); |
| ERR_LOG("error - pass\n"); |
| WARN_LOG("warn - ok\n"); |
| INFO_LOG("info - ok\n"); |
| DEBUG_LOG("debug - ok\n"); |
| |
| appSetDebugLevel(WARN_LEVEL); |
| ERR_LOG("error - fail\n"); |
| WARN_LOG("warn - pass\n"); |
| INFO_LOG("info - ok\n"); |
| DEBUG_LOG("debug - ok\n"); |
| |
| appSetDebugLevel(INFO_LEVEL); |
| ERR_LOG("error - fail\n"); |
| WARN_LOG("warn - fail\n"); |
| INFO_LOG("info - pass\n"); |
| DEBUG_LOG("debug - ok\n"); |
| |
| appSetDebugLevel(DEBUG_LEVEL); |
| ERR_LOG("error - fail\n"); |
| WARN_LOG("warn - fail\n"); |
| INFO_LOG("info - fail\n"); |
| DEBUG_LOG("debug - pass\n"); |
| } |
| |
| EXPORT void testHashParamTree() { |
| ParamTree *item; |
| ParamTree *ParamTreeHash = NULL, *tmp = NULL; /* Used for hash */ |
| const char *key; |
| |
| item = (ParamTree *)malloc(sizeof(ParamTree)); |
| item->categoryPath = "NB,Normal,,"; |
| item->paramId = 1; |
| HASH_ADD_KEYPTR(hh, ParamTreeHash, item->categoryPath, strlen(item->categoryPath), item); |
| |
| item = (ParamTree *)malloc(sizeof(ParamTree)); |
| item->categoryPath = "WB,Normal,,"; |
| item->paramId = 7; |
| HASH_ADD_KEYPTR(hh, ParamTreeHash, item->categoryPath, strlen(item->categoryPath), item); |
| |
| item = (ParamTree *)malloc(sizeof(ParamTree)); |
| item->categoryPath = "NB,Normal,0,GSM,"; |
| item->paramId = 1; |
| HASH_ADD_KEYPTR(hh, ParamTreeHash, item->categoryPath, strlen(item->categoryPath), item); |
| |
| item = (ParamTree *)malloc(sizeof(ParamTree)); |
| item->categoryPath = "NB,HAC,0,GSM"; |
| item->paramId = 0; |
| HASH_ADD_KEYPTR(hh, ParamTreeHash, item->categoryPath, strlen(item->categoryPath), item); |
| |
| /* Find string */ |
| key = "WB,,,"; |
| HASH_FIND_STR(ParamTreeHash, key, item); |
| if (item) { printf("[%s] id is %d\n", key, item->paramId); } |
| |
| /* Free hash table content */ |
| HASH_ITER(hh, ParamTreeHash, item, tmp) { |
| HASH_DEL(ParamTreeHash, item); |
| free(item); |
| } |
| } |
| |
| EXPORT void testHashParamUnit() { |
| ParamUnit *item; |
| ParamUnit *ParamUnitHash = NULL, *tmp = NULL; /* Used for hash */ |
| int key; |
| |
| item = (ParamUnit *)malloc(sizeof(ParamUnit)); |
| item->paramId = 0; |
| item->paramHash = (Param *) 0x1; |
| HASH_ADD_INT(ParamUnitHash, paramId, item); |
| |
| item = (ParamUnit *)malloc(sizeof(ParamUnit)); |
| item->paramId = 1; |
| item->paramHash = (Param *)0x2; |
| HASH_ADD_INT(ParamUnitHash, paramId, item); |
| item = (ParamUnit *)malloc(sizeof(ParamUnit)); |
| |
| item->paramId = 7; |
| item->paramHash = (Param *)0x3; |
| HASH_ADD_INT(ParamUnitHash, paramId, item); |
| |
| /* Find string */ |
| key = 0; |
| HASH_FIND_INT(ParamUnitHash, &key, item); |
| if (item) { INFO_LOG("[%d] Param is %p\n", key, item->paramHash); } |
| |
| key = 1; |
| HASH_FIND_INT(ParamUnitHash, &key, item); |
| if (item) { INFO_LOG("[%d] Param is %p\n", key, item->paramHash); } |
| |
| key = 7; |
| HASH_FIND_INT(ParamUnitHash, &key, item); |
| if (item) { INFO_LOG("[%d] Param is %p\n", key, item->paramHash); } |
| |
| /* Free hash table content */ |
| HASH_ITER(hh, ParamUnitHash, item, tmp) { |
| HASH_DEL(ParamUnitHash, item); |
| free(item); |
| } |
| } |
| |
| EXPORT void testHashParam() { |
| Param *item; |
| Param *paramHash = NULL, *tmp = NULL; /* Used for hash */ |
| const char *key; |
| |
| item = (Param *)malloc(sizeof(Param)); |
| memset(item, 0, sizeof(Param)); |
| item->name = "speech_mode_para"; |
| item->data = "0x0011,0x2233,0x4455"; |
| HASH_ADD_KEYPTR(hh, paramHash, item->name, strlen(item->name), item); |
| |
| item = (Param *)malloc(sizeof(Param)); |
| memset(item, 0, sizeof(Param)); |
| item->name = "uint_param"; |
| item->data = "4294967295"; |
| HASH_ADD_KEYPTR(hh, paramHash, item->name, strlen(item->name), item); |
| |
| item = (Param *)malloc(sizeof(Param)); |
| memset(item, 0, sizeof(Param)); |
| item->name = "float_param"; |
| item->data = "0.1234567"; |
| HASH_ADD_KEYPTR(hh, paramHash, item->name, strlen(item->name), item); |
| |
| /* Find string */ |
| key = "speech_mode_para"; |
| HASH_FIND_STR(paramHash, key, item); |
| if (item) { INFO_LOG("[%s] value is %s\n", key, (char *)item->data); } |
| |
| key = "uint_param"; |
| HASH_FIND_STR(paramHash, key, item); |
| if (item) { INFO_LOG("[%s] value is %s\n", key, (char *)item->data); } |
| |
| key = "float_param"; |
| HASH_FIND_STR(paramHash, key, item); |
| if (item) { INFO_LOG("[%s] value is %s\n", key, (char *)item->data); } |
| |
| /* Free hash table content */ |
| HASH_ITER(hh, paramHash, item, tmp) { |
| HASH_DEL(paramHash, item); |
| free(item); |
| } |
| } |
| |
| void testCb(AppHandle *appHandle, const char *audioTypeName) { |
| printf("XML file changed. (cus folder = %s, audioType = %s)\n", appHandle->xmlCusDir, audioTypeName); |
| } |
| |
| EXPORT void notifyCbTest(AppHandle *appHandle) { |
| NotifyCb *cb; |
| |
| appHandleRegXmlChangedCb(appHandle, testCb); |
| |
| LL_FOREACH(appHandle->noficyCbList, cb) { |
| (*cb->cb)(appHandle, "OK"); |
| } |
| |
| appHandleUnregXmlChangedCb(appHandle, testCb); |
| |
| LL_FOREACH(appHandle->noficyCbList, cb) { |
| (*cb->cb)(appHandle, "FAIL"); |
| } |
| } |
| |
| EXPORT void inotifyTest(const char *path) { |
| |
| #ifndef WIN32 |
| #define INOTIFY_BUF_SIZE 512 |
| /* inotify test */ |
| int wd; |
| ssize_t len; |
| char buf[INOTIFY_BUF_SIZE]; |
| char *ptr; |
| const struct inotify_event *event; |
| |
| int fd = inotify_init(); |
| if (fd < 0) { |
| printf("inotify_init failed !!!"); |
| exit(1); |
| } |
| |
| printf("inotify path = %s\n", path); |
| wd = inotify_add_watch(fd, path, IN_CLOSE_WRITE); |
| if (wd < 0) { |
| printf("inotify_add_watch failed !!!"); |
| exit(1); |
| } |
| |
| while (1) { |
| len = read(fd, buf, sizeof(buf)); |
| if (len < 0) { |
| perror("read"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* Loop over all events in the buffer */ |
| for (ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + event->len) { |
| event = (const struct inotify_event *) ptr; |
| |
| /* Print event type */ |
| if (event->mask & IN_OPEN) { |
| printf("IN_OPEN: "); |
| } |
| if (event->mask & IN_CLOSE_NOWRITE) { |
| printf("IN_CLOSE_NOWRITE: "); |
| } |
| if (event->mask & IN_CLOSE_WRITE) { |
| printf("IN_CLOSE_WRITE: "); |
| } |
| if (event->mask & IN_ACCESS) { |
| printf("IN_ACCESS: "); |
| } |
| |
| /* Print the name of the file */ |
| |
| if (event->len) { |
| printf("%s", event->name); |
| } |
| |
| /* Print type of filesystem object */ |
| |
| if (event->mask & IN_ISDIR) { |
| printf(" [directory]\n"); |
| } else { |
| printf(" [file]\n"); |
| } |
| } |
| } |
| inotify_rm_watch(fd, IN_CLOSE_NOWRITE); |
| #endif |
| } |
| |
| /*********************************** |
| * Test Steps: |
| * 1. Create thread to read/write param |
| * 2. Check the lock is work well |
| * Crash/deadlock checking |
| **********************************/ |
| EXPORT APP_STATUS testAudioTypeLockFun(AppHandle *appHandle) { |
| /* Read param */ |
| char *audioTypeName = "Speech"; |
| char *categoryPath = "Band,NB,Profile,4_pole_Headset,VolIndex,3"; |
| char *paramName = "speech_mode_para"; |
| unsigned short shortArray1[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; |
| unsigned short shortArray2[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; |
| int arraySize = 7; |
| AudioType *audioType; |
| ParamUnit *paramUnit; |
| ParamInfo *paramInfo; |
| Param *param; |
| |
| appHandle = appHandleGetInstance(); |
| |
| /* Query AudioType */ |
| audioType = appHandleGetAudioTypeByName(appHandle, audioTypeName); |
| if (!audioType) { |
| ERR_LOG("audioType is NULL\n"); |
| return APP_ERROR; |
| } |
| |
| /* Read Lock */ |
| audioTypeReadLock(audioType, __FUNCTION__); |
| |
| /* Query the ParamUnit */ |
| paramUnit = audioTypeGetParamUnit(audioType, categoryPath); |
| if (!paramUnit) { |
| ERR_LOG("paramUnit is NULL\n"); |
| return APP_ERROR; |
| } |
| |
| /* Query the param value */ |
| param = paramUnitGetParamByName(paramUnit, paramName); |
| if (!param) { |
| ERR_LOG("Error: Cannot query param value!\n"); |
| return APP_ERROR; |
| } |
| |
| /* Read unlock */ |
| audioTypeUnlock(audioType); |
| |
| utilUsleep(1); // delay time make cpu scheduling to other thread |
| |
| /* Write param */ |
| paramInfo = audioTypeGetParamInfoByName(audioType, paramName); |
| if (audioTypeSetParamData(audioType, categoryPath, paramInfo, (void *)shortArray1, arraySize) == APP_ERROR) { |
| ERR_LOG("Cannot update the param data!!\n"); |
| return APP_ERROR; |
| } |
| |
| utilUsleep(1); // delay time make cpu scheduling to other thread |
| |
| if (audioTypeSetParamData(audioType, categoryPath, paramInfo, (void *)shortArray2, arraySize) == APP_ERROR) { |
| ERR_LOG("Cannot update the param data!!\n"); |
| return APP_ERROR; |
| } |
| |
| utilUsleep(1); // delay time make cpu scheduling to other thread |
| |
| /* Save XML */ |
| audioTypeSaveAudioParamXml(audioType, XML_CUS_FOLDER_ON_DEVICE, 1); |
| |
| utilUsleep(1); // delay time make cpu scheduling to other thread |
| |
| /* Reload XML */ |
| if (appHandleReloadAudioType(appHandle, audioType->name) == APP_ERROR) { |
| ERR_LOG("Cannot reload AudioType!\n (%s)", audioType->name); |
| return APP_ERROR; |
| } |
| |
| return APP_NO_ERROR; |
| } |
| |
| EXPORT APP_STATUS testAudioTypeLock(AppHandle *appHandle) { |
| #ifndef WIN32 |
| int i; |
| pthread_t appThread; |
| void *status; |
| ThreadParam threadParam; |
| |
| threadParam.times = 50; |
| threadParam.appHandle = appHandle; |
| threadParam.fun = testAudioTypeLockFun; |
| |
| if (pthread_create(&appThread, NULL, commonThreadLoop, &threadParam)) { |
| ERR_LOG("Create app thread fail!\n"); |
| return APP_ERROR; |
| } |
| |
| for (i = 0; i < threadParam.times; i++) { |
| (*threadParam.fun)(appHandle); |
| INFO_LOG("Main thread test round = %d\n", i); |
| } |
| |
| /* Waiting 2nd thread join */ |
| pthread_join(appThread, &status); |
| #else |
| INFO_LOG("Not test this UT on windows\n"); |
| #endif |
| return APP_NO_ERROR; |
| } |
| |
| EXPORT APP_STATUS testAppHandleInitUninit() { |
| int times = 10; |
| int i; |
| for (i = 0; i < times; i++) { |
| AppHandle testAppHandle; |
| appHandleInit(&testAppHandle); |
| #ifdef WIN32 |
| appHandleParseXml(&testAppHandle, XML_FOLDER_LIST_ON_TUNING_TOOL, XML_CUS_FOLDER_ON_TUNING_TOOL); |
| #else |
| char **xmlDirFromProperty = appGetXmlDirFromProperty(); |
| if (xmlDirFromProperty) { |
| appHandleParseXml(&testAppHandle, (const char**)xmlDirFromProperty, XML_CUS_FOLDER_ON_DEVICE); |
| } else { |
| appHandleParseXml(&testAppHandle, XML_FOLDER_LIST_ON_DEVICE, XML_CUS_FOLDER_ON_DEVICE); |
| } |
| #endif |
| appHandleUninit(&testAppHandle); |
| } |
| return APP_NO_ERROR; |
| } |
| |
| /*********************************** |
| * Test Steps: |
| * 1. Reload audio type xml 100 times |
| * Memory leak / crash checking |
| **********************************/ |
| EXPORT APP_STATUS testMemoryLeak(AppHandle *appHandle) { |
| int i = 0; |
| for (i = 0; i < 100; i++) { |
| /* stress test query / release / create */ |
| AudioType *audioType = appHandleGetAudioTypeByName(appHandle, "Speech"); |
| audioType->allowReload = 1; |
| if (appHandleReloadAudioType(appHandle, "Speech") == APP_ERROR) { |
| return APP_ERROR; |
| } |
| } |
| |
| printf("Checking memory status and press enter key to continue\n"); |
| getchar(); |
| return APP_NO_ERROR; |
| } |
| |
| /*********************************** |
| * Test Steps: |
| * 1. Read param array |
| * 2. Update param array one item with 32767 |
| * 3. Repeat array size times |
| * 4. Check the result |
| **********************************/ |
| APP_STATUS testReadWriteParam(AppHandle *appHandle) { |
| size_t i, j; |
| ParamUnit *paramUnit; |
| ParamInfo *paramInfo; |
| Param *param; |
| unsigned short *shortArray; |
| size_t arraySize = 1; // The size will update by real array size latter |
| |
| const char *audioTypeName = "Speech"; |
| const char *paraName = "speech_mode_para"; |
| const char *categoryPath = "Band,NB,Profile,Normal,VolIndex,2,Network,GSM"; |
| |
| AudioType *audioType = appHandleGetAudioTypeByName(appHandle, audioTypeName); |
| |
| /* Test steps */ |
| for (j = 0; j < arraySize; j++) { |
| paramUnit = audioTypeGetParamUnit(audioType, categoryPath); |
| if (!paramUnit) { |
| ERR_LOG("Cannot find paramUnit\n"); |
| return APP_ERROR; |
| } |
| |
| param = paramUnitGetParamByName(paramUnit, paraName); |
| if (!param) { |
| ERR_LOG("Cannot query param value!\n"); |
| return APP_ERROR; |
| } |
| |
| shortArray = (unsigned short *)param->data; |
| arraySize = param->arraySize; |
| /*for(i = 0; i < param->arraySize; i++) |
| { |
| printf("[%d]0x%x\n", i, ((unsigned short*)param->data)[i]) |
| }*/ |
| |
| shortArray[j] = 32767; |
| |
| /* You should cache follow object in somewhere without query again */ |
| paramInfo = audioTypeGetParamInfoByName(audioType, paraName); |
| |
| /* The sph_in_fir param is short array type */ |
| if (audioTypeSetParamData(audioType, categoryPath, paramInfo, (void *)shortArray, param->arraySize) == APP_ERROR) { |
| return APP_ERROR; |
| } |
| } |
| |
| /* Result check */ |
| paramUnit = audioTypeGetParamUnit(audioType, categoryPath); |
| if (!paramUnit) { |
| ERR_LOG("Cannot find paramUnit\n"); |
| return APP_ERROR; |
| } |
| |
| param = paramUnitGetParamByName(paramUnit, paraName); |
| if (!param) { |
| ERR_LOG("Cannot query param value!\n"); |
| return APP_ERROR; |
| } |
| |
| shortArray = (unsigned short *)param->data; |
| for (i = 0; i < param->arraySize; i++) { |
| if (shortArray[i] != 32767) { |
| ERR_LOG("Verify short array["APP_SIZE_T_FT"] = %d != 32767\n", i, shortArray[i]); |
| return APP_ERROR; |
| } |
| } |
| |
| return APP_NO_ERROR; |
| } |