[Common] macro for max number of tensors
[platform/upstream/nnstreamer.git] / tests / unittest_util.c
1 /**
2  * SPDX-License-Identifier: LGPL-2.1-only
3  *
4  * @file        unittest_util.c
5  * @date        15 Jan 2019
6  * @brief       Unit test utility.
7  * @see         https://github.com/nnstreamer/nnstreamer
8  * @author      MyungJoo Ham <myungjoo.ham@samsung.com>
9  * @bug         No known bugs
10  */
11 #include <gst/gst.h>
12 #include <glib/gstdio.h>
13 #include <string.h>
14 #include "unittest_util.h"
15
16 /**
17  * @ref https://github.com/nnstreamer/nnstreamer/commit/7f38acb78c26f0f144b6d6fe7fb887b7431d395b
18  */
19 #if !defined(ESTRPIPE)
20 #define ESTRPIPE EPIPE
21 #endif /* !defined(ESTRPIPE) */
22
23 /**
24  * @brief Set pipeline state, wait until it's done.
25  * @return 0 success, -ESTRPIPE if failed, -ETIME if timeout happens.
26  */
27 int
28 setPipelineStateSync (GstElement * pipeline, GstState state,
29     uint32_t timeout_ms)
30 {
31   GstState cur_state = GST_STATE_VOID_PENDING;
32   GstStateChangeReturn ret;
33   guint counter = 0;
34   ret = gst_element_set_state (pipeline, state);
35
36   if (ret == GST_STATE_CHANGE_FAILURE)
37     return -ESTRPIPE;
38
39   do {
40     ret = gst_element_get_state (pipeline, &cur_state, NULL, 10 * GST_MSECOND);
41     if (ret == GST_STATE_CHANGE_FAILURE)
42       return -ESTRPIPE;
43     if (cur_state == state)
44       return 0;
45     g_usleep (10000);
46   } while ((timeout_ms / 20) > counter++);
47   return -ETIME;
48 }
49
50 /**
51  * @brief Get temp file name.
52  * @return file name (should finalize it with g_remove() and g_free() after use)
53  */
54 gchar *
55 getTempFilename (void)
56 {
57   const gchar *tmp_dir;
58   gchar *tmp_fn;
59   gint fd;
60
61   if ((tmp_dir = g_get_tmp_dir ()) == NULL) {
62     _print_log ("failed to get tmp dir");
63     return NULL;
64   }
65
66   tmp_fn = g_build_filename (tmp_dir, "nnstreamer_unittest_temp_XXXXXX", NULL);
67   fd = g_mkstemp (tmp_fn);
68
69   if (fd < 0) {
70     _print_log ("failed to create temp file %s", tmp_fn);
71     g_free (tmp_fn);
72     return NULL;
73   }
74
75   g_close (fd, NULL);
76
77   return tmp_fn;
78 }
79
80 /**
81  * @brief Remove temp file and release file name.
82  */
83 void removeTempFile (char **file_name)
84 {
85   if (*file_name) {
86     if (g_remove (*file_name) != 0) {
87       _print_log ("failed to remove temp file %s", *file_name);
88     }
89     g_free (*file_name);
90     *file_name = NULL;
91   }
92 }
93
94 /**
95  * @brief Wait until the pipeline processing the buffers
96  * @return TRUE on success, FALSE when a time-out occurs
97  */
98 gboolean
99 wait_pipeline_process_buffers (const guint * data_received,
100     guint expected_num_buffers, guint timeout_ms)
101 {
102   guint timer = 0;
103   guint tick = TEST_DEFAULT_SLEEP_TIME / 1000U;
104
105   /* Waiting for expected buffers to arrive */
106   while (*data_received < expected_num_buffers) {
107     g_usleep (TEST_DEFAULT_SLEEP_TIME);
108     timer += tick;
109     if (timer > timeout_ms)
110       return FALSE;
111   }
112   return TRUE;
113 }
114
115 /**
116  * @brief Replaces string.
117  * This function deallocates the input source string.
118  * @param[in] source The input string. This will be freed when returning the replaced string.
119  * @param[in] what The string to search for.
120  * @param[in] to The string to be replaced.
121  * @param[in] delimiters The characters which specify the place to split the string. Set NULL to replace all matched string.
122  * @param[out] count The count of replaced. Set NULL if it is unnecessary.
123  * @return Newly allocated string. The returned string should be freed with g_free().
124  */
125 gchar *
126 replace_string (gchar * source, const gchar * what, const gchar * to,
127     const gchar * delimiters, guint * count)
128 {
129   GString *builder;
130   gchar *start, *pos, *result;
131   guint changed = 0;
132   gsize len;
133
134   g_return_val_if_fail (source, NULL);
135   g_return_val_if_fail (what && to, source);
136
137   len = strlen (what);
138   start = source;
139
140   builder = g_string_new (NULL);
141   while ((pos = g_strstr_len (start, -1, what)) != NULL) {
142     gboolean skip = FALSE;
143
144     if (delimiters) {
145       const gchar *s;
146       gchar *prev, *next;
147       gboolean prev_split, next_split;
148
149       prev = next = NULL;
150       prev_split = next_split = FALSE;
151
152       if (pos != source)
153         prev = pos - 1;
154       if (*(pos + len) != '\0')
155         next = pos + len;
156
157       for (s = delimiters; *s != '\0'; ++s) {
158         if (!prev || *s == *prev)
159           prev_split = TRUE;
160         if (!next || *s == *next)
161           next_split = TRUE;
162         if (prev_split && next_split)
163           break;
164       }
165
166       if (!prev_split || !next_split)
167         skip = TRUE;
168     }
169
170     builder = g_string_append_len (builder, start, pos - start);
171
172     /* replace string if found */
173     if (skip)
174       builder = g_string_append_len (builder, pos, len);
175     else
176       builder = g_string_append (builder, to);
177
178     start = pos + len;
179     if (!skip)
180       changed++;
181   }
182
183   /* append remains */
184   builder = g_string_append (builder, start);
185   result = g_string_free (builder, FALSE);
186
187   if (count)
188     *count = changed;
189
190   g_free (source);
191   return result;
192 }
193
194 /**
195  * @brief Get available port number.
196  */
197 guint
198 get_available_port (void)
199 {
200   struct sockaddr_in sin;
201   guint port = 0;
202   gint sock;
203   socklen_t len = sizeof (struct sockaddr);
204
205   sin.sin_family = AF_INET;
206   sin.sin_addr.s_addr = INADDR_ANY;
207   sin.sin_port = htons(0);
208
209   sock = socket (AF_INET, SOCK_STREAM, 0);
210   if (sock < 0)
211     return 0;
212
213   if (bind (sock, (struct sockaddr *) &sin, sizeof (struct sockaddr)) == 0) {
214     if (getsockname (sock, (struct sockaddr *) &sin, &len) == 0) {
215       port = ntohs (sin.sin_port);
216     }
217   }
218   close (sock);
219
220   return port;
221 }
222
223 #ifdef FAKEDLOG
224 /**
225  * @brief Hijack dlog Tizen infra for unit testing to force printing out.
226  * @bug The original dlog_print returns the number of bytes printed.
227  *      This returns 0.
228  */
229 int
230 dlog_print (log_priority prio, const char *tag, const char *fmt, ...)
231 {
232   va_list arg_ptr;
233   GLogLevelFlags level;
234   switch (prio) {
235     case DLOG_FATAL:
236       level = G_LOG_LEVEL_ERROR;
237       break;
238     case DLOG_ERROR:
239       level = G_LOG_LEVEL_CRITICAL;
240       break;
241     case DLOG_WARN:
242       level = G_LOG_LEVEL_WARNING;
243       break;
244     case DLOG_INFO:
245       level = G_LOG_LEVEL_INFO;
246       break;
247     case DLOG_DEBUG:
248       level = G_LOG_LEVEL_DEBUG;
249       break;
250     default:
251       level = G_LOG_LEVEL_DEBUG;
252   }
253   va_start (arg_ptr, fmt);
254   g_logv (tag, level, fmt, arg_ptr);
255   va_end (arg_ptr);
256
257   return 0;
258 }
259 #endif