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