1 // Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #pragma once
15 
16 // Utilities for esp-idf unit tests
17 
18 #include <stdint.h>
19 #include <esp_partition.h>
20 #include "sdkconfig.h"
21 #include "freertos/FreeRTOS.h"
22 #include "freertos/task.h"
23 #include "unity.h"
24 #include "soc/soc_caps.h"
25 /* include performance pass standards header file */
26 #include "idf_performance.h"
27 #include "idf_performance_target.h"
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /* For performance check with unity test on IDF */
34 /* These macros should only be used with ESP-IDF.
35  * To use performance check, we need to first define pass standard in idf_performance.h.
36  */
37 
38 //macros call this to expand an argument instead of directly converting into str
39 #define PERFORMANCE_STR(s)   #s
40 //macros call this to contact strings after expanding them
41 #define PERFORMANCE_CON(a, b) _PERFORMANCE_CON(a, b)
42 #define _PERFORMANCE_CON(a, b) a##b
43 
44 #if !CONFIG_UNITY_IGNORE_PERFORMANCE_TESTS
45 #define _TEST_PERFORMANCE_ASSERT TEST_ASSERT
46 #else
47 #define _TEST_PERFORMANCE_ASSERT(ARG) printf("Ignoring performance test [%s]\n", PERFORMANCE_STR(ARG))
48 #endif
49 
50 #define TEST_PERFORMANCE_LESS_THAN(name, value_fmt, value, ...)  do { \
51     IDF_LOG_PERFORMANCE(#name, value_fmt, value, ##__VA_ARGS__); \
52     _TEST_PERFORMANCE_ASSERT(value < PERFORMANCE_CON(IDF_PERFORMANCE_MAX_, name)); \
53 } while(0)
54 
55 #define TEST_PERFORMANCE_GREATER_THAN(name, value_fmt, value, ...)  do { \
56     IDF_LOG_PERFORMANCE(#name, value_fmt, value, ##__VA_ARGS__); \
57     _TEST_PERFORMANCE_ASSERT(value > PERFORMANCE_CON(IDF_PERFORMANCE_MIN_, name)); \
58 } while(0)
59 
60 /* Macros to be used when performance is calculated using the cache compensated timer
61    will not assert if ccomp not supported */
62 #if SOC_CCOMP_TIMER_SUPPORTED
63 #define TEST_PERFORMANCE_CCOMP_GREATER_THAN(name, value_fmt, value, ...) \
64     TEST_PERFORMANCE_GREATER_THAN(name, value_fmt, value, ##__VA_ARGS__)
65 #define TEST_PERFORMANCE_CCOMP_LESS_THAN(name, value_fmt, value, ...) \
66     TEST_PERFORMANCE_LESS_THAN(name, value_fmt, value, ##__VA_ARGS__)
67 #else
68 #define TEST_PERFORMANCE_CCOMP_GREATER_THAN(name, value_fmt, value, ...) \
69     IDF_LOG_PERFORMANCE(#name, value_fmt, value, ##__VA_ARGS__)
70 #define TEST_PERFORMANCE_CCOMP_LESS_THAN(name, value_fmt, value, ...) \
71     IDF_LOG_PERFORMANCE(#name, value_fmt, value, ##__VA_ARGS__)
72 #endif //SOC_CCOMP_TIMER_SUPPORTED
73 
74 
75 /* @brief macro to print IDF performance
76  * @param item :        performance item name. a string pointer.
77  * @param value_fmt:    print format and unit of the value, for example: "%02fms", "%dKB"
78  * @param value :       the performance value.
79 */
80 #define IDF_LOG_PERFORMANCE(item, value_fmt, value, ...) \
81     printf("[Performance][%s]: " value_fmt "\n", item, value, ##__VA_ARGS__)
82 
83 
84 /* Some definitions applicable to Unity running in FreeRTOS */
85 #define UNITY_FREERTOS_PRIORITY CONFIG_UNITY_FREERTOS_PRIORITY
86 #define UNITY_FREERTOS_CPU CONFIG_UNITY_FREERTOS_CPU
87 #define UNITY_FREERTOS_STACK_SIZE CONFIG_UNITY_FREERTOS_STACK_SIZE
88 
89 /* Return the 'flash_test' custom data partition (type 0x55)
90    defined in the custom partition table.
91 */
92 const esp_partition_t *get_test_data_partition(void);
93 
94 /**
95  * @brief Initialize reference clock
96  *
97  * Reference clock provides timestamps at constant 1 MHz frequency, even when
98  * the APB frequency is changing.
99  */
100 void ref_clock_init(void);
101 
102 /**
103  * @brief Deinitialize reference clock
104  */
105 void ref_clock_deinit(void);
106 
107 
108 /**
109  * @brief Get reference clock timestamp
110  * @return number of microseconds since the reference clock was initialized
111  */
112 uint64_t ref_clock_get(void);
113 
114 /**
115  * @brief Entry point of the test application
116  *
117  * Starts Unity test runner in a separate task and returns.
118  */
119 void test_main(void);
120 
121 /**
122  * @brief Reset automatic leak checking which happens in unit tests.
123  *
124  * Updates recorded "before" free memory values to the free memory values
125  * at time of calling. Resets leak checker if tracing is enabled in
126  * config.
127  *
128  * This can be called if a test case does something which allocates
129  * memory on first use, for example.
130  *
131  * @note Use with care as this can mask real memory leak problems.
132  */
133 void unity_reset_leak_checks(void);
134 
135 
136 /**
137  * @brief Call this function from a test case which requires TCP/IP or
138  * LWIP functionality.
139  *
140  * @note This should be the first function the test case calls, as it will
141  * allocate memory on first use (and also reset the test case leak checker).
142  */
143 void test_case_uses_tcpip(void);
144 
145 /**
146  * @brief wait for signals with parameters.
147  *
148  * for multiple devices test cases, DUT might need to wait for other DUTs before continue testing.
149  * As all DUTs are independent, need user (or test script) interaction to make test synchronized.
150  *
151  * Here we provide signal functions for this.
152  * For example, we're testing GPIO, DUT1 has one pin connect to with DUT2.
153  * DUT2 will output high level and then DUT1 will read input.
154  * DUT1 should call `unity_wait_for_signal("output high level");` before it reads input.
155  * DUT2 should call `unity_send_signal("output high level");` after it finished setting output high level.
156  * According to the console logs:
157  *
158  * DUT1 console:
159  *
160  * ```
161  *     Waiting for signal: [output high level]!
162  *     Please press "Enter" key to once any board send this signal.
163  * ```
164  *
165  * DUT2 console:
166  *
167  * ```
168  *     Send signal: [output high level]!
169  * ```
170  *
171  * Then we press Enter key on DUT1's console, DUT1 starts to read input and then test success.
172  *
173  * Another example, we have 2 DUTs in multiple devices test, and DUT1 need to get DUT2's mac address to perform BT connection.
174  * DUT1 should call `unity_wait_for_signal_param("dut2 mac address", mac, 19);` to wait for DUT2's mac address.
175  * DUT2 should call `unity_send_signal_param("dut2 mac address", "10:20:30:40:50:60");` to send to DUT1 its mac address.
176  * According to the console logs:
177  *
178  * DUT1 console:
179  *
180  * ```
181  *     Waiting for signal: [dut2 mac address]!
182  *     Please input parameter value from any board send this signal and press "Enter" key.
183  * ```
184  *
185  * DUT2 console:
186  *
187  * ```
188  *     Send signal: [dut2 mac address][10:20:30:40:50:60]!
189  * ```
190  *
191  * @param signal_name signal name which DUT expected to wait before proceed testing
192  * @param parameter_buf buffer to receive parameter
193  * @param buf_len length of parameter_buf.
194  *                Currently we have a limitation that it will write 1 extra byte at the end of string.
195  *                We need to use a buffer with 2 bytes longer than actual string length.
196  */
197 void unity_wait_for_signal_param(const char* signal_name, char *parameter_buf, uint8_t buf_len);
198 
199 /**
200  * @brief wait for signals.
201  *
202  * @param signal_name signal name which DUT expected to wait before proceed testing
203  */
unity_wait_for_signal(const char * signal_name)204 static inline void unity_wait_for_signal(const char* signal_name)
205 {
206     unity_wait_for_signal_param(signal_name, NULL, 0);
207 }
208 
209 /**
210  * @brief DUT send signal and pass parameter to other devices.
211  *
212  * @param signal_name signal name which DUT send once it finished preparing.
213  * @param parameter a string to let remote device to receive.
214  */
215 void unity_send_signal_param(const char* signal_name, const char *parameter);
216 
217 /**
218  * @brief DUT send signal with parameter.
219  *
220  * @param signal_name signal name which DUT send once it finished preparing.
221  */
unity_send_signal(const char * signal_name)222 static inline void unity_send_signal(const char* signal_name)
223 {
224     unity_send_signal_param(signal_name, NULL);
225 }
226 
227 /**
228  * @brief convert mac string to mac address
229  *
230  * @param mac_str MAC address string with format "xx:xx:xx:xx:xx:xx"
231  * @param[out] mac_addr store converted MAC address
232  */
233 bool unity_util_convert_mac_from_string(const char* mac_str, uint8_t *mac_addr);
234 
235 /**
236  * @brief Leak for components
237  */
238 typedef enum {
239     COMP_LEAK_GENERAL = 0,  /**< Leak by default */
240     COMP_LEAK_LWIP,         /**< Leak for LWIP */
241     COMP_LEAK_NVS,          /**< Leak for NVS */
242     COMP_LEAK_ALL,          /**< Use for getting the summary leak level */
243 } esp_comp_leak_t;
244 
245 /**
246  * @brief Type of leak
247  */
248 typedef enum {
249     TYPE_LEAK_WARNING = 0,  /**< Warning level of leak */
250     TYPE_LEAK_CRITICAL,     /**< Critical level of leak */
251     TYPE_LEAK_MAX,          /**< Max number of leak levels */
252 } esp_type_leak_t;
253 
254 /**
255  * @brief Set a leak level for the required type and component.
256  *
257  * @param[in] leak_level Level of leak
258  * @param[in] type       Type of leak
259  * @param[in] component  Name of component
260  *
261  * return ESP_OK: Successful.
262  *        ESP_ERR_INVALID_ARG: Invalid argument.
263  */
264 esp_err_t test_utils_set_leak_level(size_t leak_level, esp_type_leak_t type, esp_comp_leak_t component);
265 
266 /**
267  * @brief Get a leak level for the required type and component.
268  *
269  * @param[in] type       Type of leak.
270  * @param[in] component  Name of component. If COMP_LEAK_ALL, then the level will be summarized for all components.
271  * return Leak level
272  */
273 size_t test_utils_get_leak_level(esp_type_leak_t type, esp_comp_leak_t component);
274 
275 
276 typedef struct test_utils_exhaust_memory_record_s *test_utils_exhaust_memory_rec;
277 
278 /**
279  * Limit the largest free block of memory with a particular capability set to
280  * 'limit' bytes (meaning an allocation of 'limit' should succeed at least once,
281  * but any allocation of more bytes will fail.)
282  *
283  * Returns a record pointer which needs to be passed back in to test_utils_free_exhausted_memory
284  * before the test completes, to avoid a major memory leak.
285  *
286  * @param caps Capabilities of memory to exhause
287  * @param limit The size to limit largest free block to
288  * @return Record pointer to pass to test_utils_free_exhausted_memory() once done
289  */
290 test_utils_exhaust_memory_rec test_utils_exhaust_memory(uint32_t caps, size_t limit);
291 
292 
293 /**
294  * Call to free memory which was taken up by test_utils_exhaust_memory() call
295  *
296  * @param rec Result previously returned from test_utils_exhaust_memory()
297  */
298 void test_utils_free_exhausted_memory(test_utils_exhaust_memory_rec rec);
299 
300 
301 /**
302  * @brief Delete task ensuring dynamic memory (for stack, tcb etc.) gets freed up immediately
303  *
304  * @param[in] thandle    Handle of task to be deleted (should not be NULL or self handle)
305  */
306 void test_utils_task_delete(TaskHandle_t thandle);
307 
308 #ifdef __cplusplus
309 }
310 #endif
311