fixup! Fix hanging on pthread_cond_destroy during cancellation of thread by broadcast...
[platform/core/api/sound-pool.git] / test / sound_pool_test.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "logger.h"
18 #include "proxy.h"
19
20 #include <string.h>
21 #include <stdio.h>
22 #include <termios.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <stdlib.h>
26
27 #define KEY_CODE_ESCAPE      27
28 #define KEY_CODE_BACKSPACE   127
29 #define KEY_CODE_TAB         9
30 #define KEY_CODE_ARROW_UP    65
31 #define KEY_CODE_ARROW_DOWN  66
32 #define KEY_CODE_ARROW_RIGHT 67
33 #define KEY_CODE_ARROW_LEFT  68
34
35 /* The list data structure to keep history of the test suite commands */
36 typedef struct __cmd_history_s {
37         struct __cmd_history_s *prev;
38         struct __cmd_history_s *next;
39         char cmd[MAX_COMMAND_LINE_LEN];
40 } _cmd_history_t;
41
42 static _cmd_history_t *_cmd_history_tail = NULL;
43 static _cmd_history_t *_cmd_history_curp = NULL;
44 static char OUTPUT_LOG_FILE[MAX_PATH_LEN] = "out.log";
45
46 void print_usage()
47 {
48         printf("Usage: sound_pool_test [options]                              \n");
49         printf("Test Suite for testing Tizen SoundPool module                 \n");
50         printf("-h, --help             - shows this help;                     \n");
51         printf("-s, --script=SCRIPT    - executes commands from the text file \n"
52                         "                         directly after start;                \n");
53         printf("-t, --target=TARGET(S) - selects the target or targets to     \n"
54                         "                         output logs. Possible targets are:   \n"
55                         "                         stderr, dlog, file. You can also     \n"
56                         "                         select multiple targets using coma.  \n"
57                         "                         for example,                         \n"
58                         "                         > sound_pool_test -t stderr,file     \n"
59                         "                         will output both in standard         \n"
60                         "                         error and file;                      \n");
61         printf("-f, --file=FILEPATH    - selects file for file output logging.\n"
62                         "                         Works only in -t argument value      \n"
63                         "                         includes 'file' target;              \n");
64 }
65
66 _cmd_history_t *add_cmd_to_history(const char *cmd)
67 {
68         if (!cmd)
69                 return NULL;
70
71         if (!_cmd_history_tail) {
72                 _cmd_history_tail = malloc(sizeof(_cmd_history_t));
73                 if (!_cmd_history_tail)
74                         return NULL;
75                 _cmd_history_tail->prev = NULL;
76                 _cmd_history_tail->next = NULL;
77         } else {
78                 _cmd_history_tail->next = malloc(sizeof(_cmd_history_t));
79                 if (!_cmd_history_tail->next)
80                         return NULL;
81                 _cmd_history_tail->next->prev = _cmd_history_tail;
82                 _cmd_history_tail->next->next = NULL;
83                 _cmd_history_tail = _cmd_history_tail->next;
84         }
85
86         strncpy(_cmd_history_tail->cmd, cmd, MAX_COMMAND_LINE_LEN - 1);
87         _cmd_history_tail->cmd[MAX_COMMAND_LINE_LEN - 1] = '\0';
88         _cmd_history_curp = _cmd_history_tail;
89         return _cmd_history_tail;
90 }
91
92 const char *pop_up_curp_from_cmd_history()
93 {
94         if (!_cmd_history_curp)
95                 return NULL;
96
97         const char *curp_cmd = _cmd_history_curp->cmd;
98         if (_cmd_history_curp->prev)
99                 _cmd_history_curp = _cmd_history_curp->prev;
100         return curp_cmd;
101 }
102
103 const char *pop_down_curp_from_cmd_history()
104 {
105         if (!_cmd_history_curp)
106                 return NULL;
107
108         const char *curp_cmd = _cmd_history_curp->cmd;
109         if (_cmd_history_curp->next)
110                 _cmd_history_curp = _cmd_history_curp->next;
111         return curp_cmd;
112 }
113
114 /* Searches the same part of two strings from the start and returns the length
115    of this part. For example, for the strings "Big Troll" and "Big troll" value
116    4 will be returned (the same part is "Big "). */
117 size_t get_identical_start_len(const char *str1, const char *str2)
118 {
119         size_t len1 = strnlen(str1, MAX_COMMAND_LINE_LEN);
120         size_t len2 = strnlen(str2, MAX_COMMAND_LINE_LEN);
121         size_t idx = 0;
122         while (idx < len1 && idx < len2) {
123                 if (str1[idx] != str2[idx])
124                         break;
125                 ++idx;
126         }
127         return idx;
128 }
129
130 size_t auto_fill(const char *cmd_start, char fill_hint[MAX_COMMAND_LINE_LEN])
131 {
132         size_t idx = 0;
133         size_t cmd_start_len = strnlen(cmd_start, MAX_COMMAND_LINE_LEN);
134
135         char auto_fill[MAX_COMMAND_LINE_LEN] = { '\0' };
136         size_t fill_found = 0;
137
138         for (; idx < CMD_COUNT; ++idx) {
139                 if (strncmp(cmd_start, cmd_list[idx], cmd_start_len) == 0) {
140                         if (!fill_found) {
141                                 strncpy(auto_fill, cmd_list[idx], MAX_COMMAND_LINE_LEN - 1);
142                                 fill_found = strnlen(auto_fill, MAX_COMMAND_LINE_LEN - 1);
143                         } else {
144                                 fill_found = get_identical_start_len(auto_fill, cmd_list[idx]);
145                                 auto_fill[fill_found] = '\0';
146                         }
147                 }
148         }
149
150         if (!fill_found)
151                 strncpy(fill_hint, cmd_start, MAX_COMMAND_LINE_LEN - 1);
152         else
153                 strncpy(fill_hint, auto_fill, MAX_COMMAND_LINE_LEN - 1);
154
155         fill_hint[MAX_COMMAND_LINE_LEN - 1] = '\0';
156
157         return fill_found;
158 }
159
160 size_t print_cmd_prompt()
161 {
162         const char *prompt = "sound-pool-ts-cmd > ";
163         printf("%s", prompt);
164         /* Return the length of comand prompt c-string */
165         return strnlen(prompt, MAX_COMMAND_LINE_LEN);
166 }
167
168 int getch(void)
169 {
170         struct termios oldattr, newattr;
171         int ch;
172         tcgetattr(STDIN_FILENO, &oldattr);
173         newattr = oldattr;
174         newattr.c_lflag &= ~(ICANON | ECHO);
175         tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
176         ch = getchar();
177         tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
178         return ch;
179 }
180
181 size_t ts_getline(char *cmd_line)
182 {
183         if (!cmd_line)
184                 return 0;
185
186         print_cmd_prompt();
187
188         /* Read whole line */
189         int ci = 0;
190         char cc = '\0';
191         int c = 0;
192         while ((c = getch()) != EOF && (cc = (char)c) != '\n' &&
193                         ci < MAX_COMMAND_LINE_LEN - 1) {
194                 if (cc == KEY_CODE_ESCAPE) { /* Arrow keys */
195                         getch();
196                         c = getch();
197                         if (c == EOF)
198                                 continue;
199                         cc = (char)c; /* Here is particular arrow code */
200                         const char *curp_cmd = NULL;
201                         if (cc == KEY_CODE_ARROW_UP) {
202                                 if ((curp_cmd = pop_up_curp_from_cmd_history())) {
203                                         while (ci-- != 0)
204                                                 printf("\b \b");
205                                         printf("%s", curp_cmd);
206                                         strncpy(cmd_line, curp_cmd, MAX_COMMAND_LINE_LEN);
207                                         ci = strnlen(curp_cmd, MAX_COMMAND_LINE_LEN);
208                                 }
209                         } else if (cc == KEY_CODE_ARROW_DOWN) {
210                                 if ((curp_cmd = pop_down_curp_from_cmd_history())) {
211                                         while (ci-- != 0)
212                                                 printf("\b \b");
213                                         printf("%s", curp_cmd);
214                                         strncpy(cmd_line, curp_cmd, MAX_COMMAND_LINE_LEN);
215                                         ci = strnlen(curp_cmd, MAX_COMMAND_LINE_LEN);
216                                 }
217                         }
218                         continue;
219                 }
220                 if (cc == KEY_CODE_BACKSPACE) { /* Backspace key */
221                         if (ci != 0) {
222                                 printf("\b \b");
223                                 cmd_line[ci--] = '\0';
224                         }
225                         continue;
226                 }
227                 if (cc == KEY_CODE_TAB) { /* Tab key */
228                         size_t hint_len = auto_fill(cmd_line, cmd_line);
229                         while (ci < hint_len)
230                                 printf("%c", cmd_line[ci++]);
231                         cmd_line[ci] = '\0';
232                         continue;
233                 }
234                 cmd_line[ci++] = cc;
235                 cmd_line[ci] = '\0';
236                 printf("%c", cc);
237         }
238
239         printf("\n");
240
241         return ci + 1;
242 }
243
244 int main(int argc, char* argv[])
245 {
246         _logger_set_log_tag("TIZEN_SOUND_POOL_TEST_SUITE");
247         _logger_set_logging_mode(LOG_MODE_STDERR | LOG_MODE_DLOG);
248
249 #   define OPTIONS "s:f:t:h"
250         struct option options[] = {
251                 { "script",  required_argument, NULL, 's' },
252                 { "logfile", required_argument, NULL, 'f' },
253                 { "target",  required_argument, NULL, 't' },
254                 { "help",    no_argument,       NULL, 'h' },
255                 { NULL, 0, NULL, 0 }
256         };
257
258         char commands[MAX_COMMAND_LINE_LEN] = { '\0' };
259         size_t last_cmd_end = 0;
260
261         int opt = 0;
262         int do_print_usage = 0;
263         int do_set_file = 0;
264         while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) {
265                 switch (opt) {
266                 case 's': {
267                         snprintf(commands + last_cmd_end, MAX_COMMAND_LINE_LEN - 1,
268                                         "%s %s\n", CMD_EXECUTE_SCRIPT, optarg);
269                         last_cmd_end +=
270                                         strnlen(commands + last_cmd_end, MAX_COMMAND_LINE_LEN) + 1;
271                         break;
272                 }
273                 case 'f': {
274                         _logger_set_file(optarg);
275                         do_set_file--;
276                         break;
277                 }
278                 case 't': {
279                         int log_mode = LOG_MODE_NONE;
280                         char *usr_ptr = NULL;
281                         char *token = strtok_r(optarg, ",", &usr_ptr);
282
283                         while (token != NULL) {
284                                 if (strncmp(token, "stderr", MAX_MSG_LEN) == 0) {
285                                         log_mode |= LOG_MODE_STDERR;
286                                 } else if (strncmp(token, "file", MAX_MSG_LEN) == 0) {
287                                         log_mode |= LOG_MODE_FILE;
288                                         do_set_file++;
289                                 } else if (strncmp(token, "dlog", MAX_MSG_LEN) == 0) {
290                                         log_mode |= LOG_MODE_DLOG;
291                                 } else {
292                                         _printf(CMD_COLOR_RED, "%s target is not supported! "
293                                                         "Use one (or combination separated by coma) "
294                                                         "from the list: dlog, stderr, and dlog.\n", token);
295                                 }
296                                 token = strtok_r(NULL, ", ", &usr_ptr);
297                         }
298
299                         if (log_mode != LOG_MODE_NONE)
300                                 _logger_set_logging_mode(log_mode);
301                         break;
302                 }
303                 case 'h':
304                 case '?': {
305                         do_print_usage = 1;
306                         break;
307                 }
308                 default:
309                         break;
310                 }
311         }
312
313         if (do_print_usage != 0)
314                 print_usage();
315
316         if (do_set_file > 0)
317                 _logger_set_file(OUTPUT_LOG_FILE);
318
319         char *ccmd = commands;
320
321         while (ccmd[0] != '\0') {
322                 if (_exec_cmd(ccmd) == UCMD) {
323                         _printf(CMD_COLOR_RED,
324                                         "Unknown command! Type 'help' for command help!\n");
325                 }
326                 ccmd += strnlen(ccmd, MAX_COMMAND_LINE_LEN) + 1;
327         }
328
329         char cmd_line[MAX_COMMAND_LINE_LEN];
330         size_t cmd_line_len = 0;
331
332         while ((cmd_line_len = ts_getline(cmd_line))) {
333                 if (cmd_line_len == 1)
334                         continue;
335
336                 /* Try to execute commands parsed from the line: */
337                 int res = _exec_cmd(cmd_line);
338                 if (res == EXIT)
339                         break;
340
341                 if (res == UCMD)
342                         _printf(CMD_COLOR_RED,
343                                         "Unknown command! Type 'help' for command help!\n");
344
345                 add_cmd_to_history(cmd_line);
346         }
347
348         return 0;
349 }