add new qloud-c-sdk component

This commit is contained in:
mculover666
2022-03-25 10:06:56 +08:00
parent 565cd29e94
commit a3ac2e56d8
166 changed files with 35027 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
file(GLOB src ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
set(inc ${CMAKE_CURRENT_SOURCE_DIR}/inc/)
set(src_common ${src_common} ${src} PARENT_SCOPE)
set(inc_common ${inc_common} ${inc} PARENT_SCOPE)
if( ${CONFIG_IOT_TEST} STREQUAL "ON")
file(GLOB src_unit_test ${CMAKE_CURRENT_SOURCE_DIR}/test/*.cc)
set(src_test ${src_test} ${src_unit_test} PARENT_SCOPE)
endif()

View File

@@ -0,0 +1,104 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_downloader.h
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-10-20
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-10-20 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/**
* @brief Downloader status.
*
*/
typedef enum {
UTILS_DOWNLOADER_STATUS_SUCCESS = 0,
UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED,
UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED,
UTILS_DOWNLOADER_STATUS_NETWORK_FAILED
} UtilsDownloaderStatus;
/**
* @brief Downloader function.
*
*/
typedef struct {
// memory
void* (*downloader_malloc)(size_t len); /**< user malloc */
void (*downloader_free)(void* val); /**< user free */
// break point
int (*break_point_init)(void* usr_data); /**< init break point, read from flash or file */
void (*break_point_deinit)(void* usr_data); /**< deinit break point */
int (*break_point_set)(void* usr_data); /**< set break point structure */
int (*break_point_save)(void* usr_data); /**< save break point in flash or file */
int (*break_point_check)(void* usr_data); /**< check break point valid */
int (*break_point_restore)(void* usr_data); /**< restore break point */
// data download
int (*data_download_init)(void* usr_data); /**< init data download, such as http connect */
void (*data_download_deinit)(void* usr_data); /**< deinit data download, such as http disconnect */
int (*data_download_is_over)(void* usr_data); /**< check if download finish */
int (*data_download_recv)(void* usr_data); /**< recv data, such as http recv */
int (*data_download_save)(void* usr_data); /**< save data, such as write firmware to flash */
int (*data_download_finish)(void* usr_data, UtilsDownloaderStatus status); /**< process result */
} UtilsDownloaderFunction;
/**
* @brief Init downloader.
*
* @param[in] func download function should implement
* @param[in] usr_data user data using in function
* @return pointer to downloader
*/
void* utils_downloader_init(UtilsDownloaderFunction func, void* usr_data);
/**
* @brief Process download using function.
*
* @param[in,out] handle pointer to downloader
* @return -1 for fail, others see data_download_finish
*/
int utils_downloader_process(void* handle);
/**
* @brief Deinit downloader.
*
* @param[in,out] handle pointer to downloader
*/
void utils_downloader_deinit(void* handle);
#ifdef __cplusplus
}
#endif
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_DOWNLOADER_H_

View File

@@ -0,0 +1,108 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_json.h
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-07-24
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-07-24 <td>1.0 <td>fancyxu <td>first commit
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>fix bug and add utils_json_value_data_get
* </table>
*/
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
/**
* @brief Json value type
*
*/
typedef enum {
UTILS_JSON_VALUE_TYPE_INT32 = 0,
UTILS_JSON_VALUE_TYPE_INT64,
UTILS_JSON_VALUE_TYPE_UINT32,
UTILS_JSON_VALUE_TYPE_UINT64,
UTILS_JSON_VALUE_TYPE_FLOAT,
UTILS_JSON_VALUE_TYPE_DOUBLE,
UTILS_JSON_VALUE_TYPE_BOOLEAN,
} UtilsJsonValueType;
/**
* @brief Json value
*
*/
typedef struct {
const char *value;
int value_len;
} UtilsJsonValue;
/**
* @brief Get value from json string. Not strict, just for iot scene, we suppose all the string is valid json.
*
* @param[in] key key in json, support nesting with '.'
* @param[in] key_len key len
* @param[in] src json string
* @param[in] src_len src length
* @param[out] value value
* @return 0 for success
*/
int utils_json_value_get(const char *key, int key_len, const char *src, int src_len, UtilsJsonValue *value);
/**
* @brief Get data of value with type.
*
* @param[in] value @see UtilsJsonValue
* @param[in] type value type, string can use value directly @see UtilsJsonValueType
* @param[out] data data pointer, user should match the type
* @return 0 for success
*/
int utils_json_value_data_get(UtilsJsonValue value, UtilsJsonValueType type, void *data);
/**
* @brief Return unsigned int value of key in json.
*
* @return 0 for success
*/
int utils_json_get_uint32(const char *key, int key_len, const char *src, int src_len, uint32_t *data);
/**
* @brief Remove '\\' in json string.
*
* @param[in,out] src string to transfer
* @param[in] src_len string len
* @return length after transfer
*/
int utils_json_strip_transfer(char *src, int src_len);
#ifdef __cplusplus
}
#endif
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_JSON_H_

View File

@@ -0,0 +1,140 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_list.h
* @brief header file for utils list
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-25 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
/**
* @brief ListNode iterator direction.
*
*/
typedef enum {
LIST_HEAD,
LIST_TAIL,
} UtilsListDirection;
/**
* @brief ListNode process result of OnNodeProcessHandle.
*
*/
typedef enum {
LIST_TRAVERSE_CONTINUE,
LIST_TRAVERSE_BREAK,
} UtilsListResult;
/**
* @brief Utils list function.
*
*/
typedef struct {
void *(*list_malloc)(size_t len);
void (*list_free)(void *val);
void *(*list_lock_init)(void);
void (*list_lock)(void *lock);
void (*list_unlock)(void *lock);
void (*list_lock_deinit)(void *lock);
} UtilsListFunc;
/**
* @brief Node process handle called by utils_list_process.
*
*/
typedef UtilsListResult (*OnNodeProcessHandle)(void *list, void *node, void *val, void *usr_data);
/**
* @brief Create list with max len, return NULL if fail.
*
* @param[in] func function needed by list
* @param[in] max_len max_len of list
* @return pointer to list, NULL for failed
*/
void *utils_list_create(UtilsListFunc func, int max_len);
/**
* @brief Destroy list.
*
* @param[in] list pointer to list
*/
void utils_list_destroy(void *list);
/**
* @brief Get list len.
*
* @param[in] list pointer to list
* @return len of list
*/
int utils_list_len_get(void *list);
/**
* @brief Push the node to list tail, return NULL if node invalid.
*
* @param[in] list pointer to list
* @param[in] val value needed to push to list
* @return pointer to node, NULL for failed
*/
void *utils_list_push(void *list, void *val);
/**
* @brief Pop the val from list head, return NULL if list empty.
*
* @param[in] list pointer to list
* @return val in the head node
*/
void *utils_list_pop(void *list);
/**
* @brief Delete the node in list and release the resource.
*
* @param[in] list pointer to list
* @param[in] node pointer to node needed remove
*/
void utils_list_remove(void *list, void *node);
/**
* @brief Process list using handle function.
*
* @param[in] list pointer to list
* @param[in] direction direction to traverse
* @param[in] handle process function @see OnNodeProcessHandle
* @param[in,out] usr_data usr data to pass to OnNodeProcessHandle
*/
void utils_list_process(void *list, uint8_t direction, OnNodeProcessHandle handle, void *usr_data);
#ifdef __cplusplus
}
#endif
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LIST_H_

View File

@@ -0,0 +1,121 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_log.h
* @brief header file for utils log
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-28
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#ifndef IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_
#define IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
/**
* @brief SDK log print/upload level.
*
*/
typedef enum {
LOG_LEVEL_DISABLE = 0, /**< disable log print/upload */
LOG_LEVEL_ERROR = 1, /**< error log level */
LOG_LEVEL_WARN = 2, /**< warning log level */
LOG_LEVEL_INFO = 3, /**< info log level */
LOG_LEVEL_DEBUG = 4, /**< debug log level */
} LogLevel;
/**
* @brief User's self defined log handler callback.
*
*/
typedef struct {
void *(*log_malloc)(size_t len);
void (*log_free)(void *val);
void (*log_handle)(const char *message);
void (*log_upload)(int log_level, const char *message);
void (*log_printf)(const char *fmt, ...);
char *(*log_get_current_time_str)(void);
void *(*log_mutex_create)(void);
void (*log_mutex_lock)(void *mutex);
void (*log_mutex_unlock)(void *mutex);
void (*log_mutex_destroy)(void *mutex);
} LogHandleFunc;
/**
* @brief Init log with func, log level, max log size.
*
* @param[in] func function should be implement for utils log
* @param[in] log_level @see LogLevel
* @param[in] max_log_size max size of log to print
* @return 0 for success
*/
int utils_log_init(LogHandleFunc func, LogLevel log_level, int max_log_size);
/**
* @brief Deinit log.
*
*/
void utils_log_deinit(void);
/**
* @brief Set log level.
*
* @param log_level @see LogLevel
*/
void utils_log_set_level(LogLevel log_level);
/**
* @brief Get log level.
*
* @return @see LogLevel
*/
LogLevel utils_log_get_level(void);
/**
* @brief Generate log if level higher than set.
*
* @param[in] file file path
* @param[in] func function where generate log
* @param[in] line line of source file where genertate log
* @param[in] level @see LogLevel
* @param[in] fmt format of log content
*/
void utils_log_gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...);
// Simple APIs for log generation in different level
#define Log_d(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
#define Log_i(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
#define Log_w(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_WARN, fmt, ##__VA_ARGS__)
#define Log_e(fmt, ...) utils_log_gen(__FILE__, __FUNCTION__, __LINE__, LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif // IOT_HUB_DEVICE_C_SDK_COMMON_UTILS_INC_UTILS_LOG_H_

View File

@@ -0,0 +1,142 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_downloader.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-10-18
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-10-18 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_downloader.h"
/**
* @brief Downloader.
*
*/
typedef struct {
UtilsDownloaderFunction func;
void* usr_data;
} UtilsDownloader;
/**
* @brief Init downloader.
*
* @param[in] func download function should implement
* @param[in] usr_data user data using in function
* @return pointer to downloader
*/
void* utils_downloader_init(UtilsDownloaderFunction func, void* usr_data)
{
if (!func.downloader_malloc) {
return NULL;
}
UtilsDownloader* handle = func.downloader_malloc(sizeof(UtilsDownloader));
if (!handle) {
return NULL;
}
handle->func = func;
handle->usr_data = usr_data;
return handle;
}
/**
* @brief Process download using function.
*
* @param[in,out] handle pointer to downloader
* @return -1 for fail, others see data_download_finish
*/
int utils_downloader_process(void* handle)
{
int rc = -1;
UtilsDownloader* downloader = handle;
UtilsDownloaderStatus status = UTILS_DOWNLOADER_STATUS_SUCCESS;
if (!handle) {
return -1;
}
rc = downloader->func.break_point_init(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
// if check ok, restore from break point, otherwise set break point
rc = downloader->func.break_point_check(downloader->usr_data)
? downloader->func.break_point_set(downloader->usr_data)
: downloader->func.break_point_restore(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
rc = downloader->func.data_download_init(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
goto exit;
}
while (!downloader->func.data_download_is_over(downloader->usr_data)) {
rc = downloader->func.data_download_recv(downloader->usr_data);
if (rc < 0) {
status = UTILS_DOWNLOADER_STATUS_NETWORK_FAILED;
goto exit;
}
rc = downloader->func.data_download_save(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_DATA_DOWNLOAD_FAILED;
goto exit;
}
rc = downloader->func.break_point_save(downloader->usr_data);
if (rc) {
status = UTILS_DOWNLOADER_STATUS_BREAK_POINT_FAILED;
goto exit;
}
}
exit:
rc = downloader->func.data_download_finish(downloader->usr_data, status);
downloader->func.break_point_deinit(downloader->usr_data);
downloader->func.data_download_deinit(downloader->usr_data);
return rc;
}
/**
* @brief Deinit downloader.
*
* @param[in,out] handle pointer to downloader
*/
void utils_downloader_deinit(void* handle)
{
UtilsDownloader* downloader = handle;
if (!handle) {
return;
}
downloader->func.downloader_free(handle);
}

View File

@@ -0,0 +1,577 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_json.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-07-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-07-25 <td>1.0 <td>fancyxu <td>first commit
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>fix bug and add utils_json_value_data_get
* </table>
*/
#include "utils_json.h"
/**
* @brief Delimiter of json
*
*/
typedef enum {
JSON_DELIMITER_ARRAY_BEGIN = '[',
JSON_DELIMITER_ARRAY_END = ']',
JSON_DELIMITER_OBJECT_BEGIN = '{',
JSON_DELIMITER_OBJECT_END = '}',
JSON_DELIMITER_KEY = '"',
JSON_DELIMITER_VALUE = ':',
JSON_DELIMITER_ELEMENT_END = ',',
JSON_DELIMITER_TYPE_STRING = '"',
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER = 'T',
JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER = 't',
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER = 'F',
JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER = 'f',
JSON_DELIMITER_TYPE_NULL_UPPER = 'N',
JSON_DELIMITER_TYPE_NULL_LOWER = 'n',
JSON_DELIMITER_SPACE = ' ',
JSON_DELIMITER_NONE = 0,
} JsonDelimiter;
/**
* @brief Element type support
*
*/
typedef enum {
JSON_ELEMENT_ARRAY = 0,
JSON_ELEMENT_OBJECT,
JSON_ELEMENT_VALUE_STRING,
JSON_ELEMENT_VALUE_NUMBER,
JSON_ELEMENT_VALUE_BOOLEAN,
JSON_ELEMENT_VALUE_NULL,
JSON_ELEMENT_KEY,
} JsonElementType;
/**
* @brief Json Element
*
*/
typedef struct {
JsonElementType type;
char *pos_begin;
char *pos_end;
int element_len;
} JsonElement;
#define json_key JsonElement
#define json_value JsonElement
/**
* @brief Is delimiter begin or end matched
*
*/
typedef struct {
int (*is_begin_matched)(char *str);
int (*is_end_matched)(char *str, int *offset);
} IsDelimiterMatched;
/**
* @brief For array type, when meets '[', means depth++
*
* @param[in] str pointer to char
* @return true for matched
*/
static int _is_array_begin_matched(char *str)
{
return *str == JSON_DELIMITER_ARRAY_BEGIN;
}
/**
* @brief For array type, when meets ']', means depth--
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_array_end_matched(char *str, int *offset)
{
return *str == JSON_DELIMITER_ARRAY_END;
}
/**
* @brief For object type, when meets '{', means depth++
*
* @param[in] str pointer to char
* @return true for matched
*/
static int _is_object_begin_matched(char *str)
{
return *str == JSON_DELIMITER_OBJECT_BEGIN;
}
/**
* @brief For object type, when meets '}', means depth--
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_object_end_matched(char *str, int *offset)
{
return *str == JSON_DELIMITER_OBJECT_END;
}
/**
* @brief For string type, when meets '"', but not "\"", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_string_end_matched(char *str, int *offset)
{
return *str == '"' && *(str - 1) != '\\';
}
/**
* @brief For number type, when meets not '0~9', '.' or 'f' for float, means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move
* @return true for matched
*/
static int _is_number_end_matched(char *str, int *offset)
{
return (*str < '0' || *str > '9') && *str != '.' && *str != 'f' && *str != '-';
}
/**
* @brief For boolen type, when meets "true", "True", "false" or "False", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move, -1 means error
* @return true for matched
*/
static int _is_boolean_end_matched(char *str, int *offset)
{
*offset = !strncmp(str, "true", 4) || !strncmp(str, "TRUE", 4) ? 4 : *offset;
*offset = !strncmp(str, "false", 5) || !strncmp(str, "FALSE", 5) ? 5 : *offset;
if (*offset == 0) {
*offset = -1; // -1 means error
}
return 1;
}
/**
* @brief For boolen type, when meets "null", "NULL", means the end
*
* @param[in] str pointer to char
* @param[out] offset offset for pointer to move, -1 means error
* @return true for matched
*/
static int _is_null_end_matched(char *str, int *offset)
{
*offset = !strncmp(str, "null", 4) || !strncmp(str, "NULL", 4) ? 4 : 0;
if (*offset == 0) {
*offset = -1; // -1 means error
}
return 1;
}
/**
* @brief Table of matched function of elements
*
*/
static IsDelimiterMatched sg_element_matched_func[] = {
{_is_array_begin_matched, _is_array_end_matched}, // JSON_ELEMENT_ARRAY
{_is_object_begin_matched, _is_object_end_matched}, // JSON_ELEMENT_OBJECT
{NULL, _is_string_end_matched}, // JSON_ELEMENT_VALUE_STRING
{NULL, _is_number_end_matched}, // JSON_ELEMENT_VALUE_NUMBER
{NULL, _is_boolean_end_matched}, // JSON_ELEMENT_VALUE_BOOLEAN
{NULL, _is_null_end_matched}, // JSON_ELEMENT_VALUE_NULL
{NULL, NULL}, // JSON_ELEMENT_KEY
};
/**
* @brief Increase pos and decrease remain len
*
* @param[in,out] pos current pos
* @param[in,out] len current len
*/
static void _increase_pos(char **pos, int *len)
{
(*pos)++;
(*len)--;
};
/**
* @brief Find delimiter and return pos
*
* @param[in] ch delimiter character
* @param[in] spilt_char if 0 then spilt nothing but delimiter
* @param[in] str input string
* @param[in,out] remain_len remaining length
* @return NULL for failed
*/
static char *_find_json_delimiter(JsonDelimiter ch, char spilt_char, char *str, int *remain_len)
{
char *pos = NULL;
while ((*remain_len) > 0 && str && *str) {
if ((!spilt_char && *str != ch) || (spilt_char && *str == spilt_char)) {
_increase_pos(&str, remain_len);
continue;
}
pos = (*str == ch) ? str : 0;
break;
}
return pos;
}
/**
* @brief Find element end
*
* @param[in] is_begin_matched using in nesting
* @param[in] is_end_matched match end
* @param[in] str input string
* @param[in,out] remain_len remaining length
* @return NULL for failed
*/
static char *_find_json_value_element_end(int (*is_begin_matched)(char *), int (*is_end_matched)(char *, int *),
char *str, int *remain_len)
{
int offset = 0;
int depth = 0;
char *pos = NULL;
while (str && *str) {
offset = 0;
if (*remain_len <= 0) {
return NULL;
}
if (is_begin_matched) {
if (is_begin_matched(str)) {
depth++;
}
}
if (is_end_matched(str, &offset)) {
if (!depth) {
if (offset < 0) {
break; // failed
}
pos = str + offset;
(*remain_len) -= offset;
break;
}
if (depth > 0) {
depth--;
}
}
str++;
(*remain_len)--;
}
return pos;
}
/**
* @brief Get json key from string
*
* @param[in] node_begin string begin
* @param[in,out] remain_len remaining length
* @param[out] key key node
* @return 0 for success
*/
static int _get_json_key(char *node_begin, int *remain_len, json_key *key)
{
char *key_begin = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_SPACE, node_begin, remain_len);
if (!key_begin) {
return -1;
}
_increase_pos(&key_begin, remain_len);
char *key_end = _find_json_delimiter(JSON_DELIMITER_KEY, JSON_DELIMITER_NONE, key_begin, remain_len);
if (!key_end) {
return -1;
}
key->type = JSON_ELEMENT_KEY;
key->pos_begin = key_begin;
key->pos_end = key_end;
key->element_len = key_end - key_begin;
return 0;
}
/**
* @brief Get json value from key end
*
* @param[in] key_end end of key
* @param[in,out] remain_len remaining length
* @param[out] value value node
* @return 0 for success
*/
static int _get_json_value(char *key_end, int *remain_len, json_value *value)
{
char *value_begin = _find_json_delimiter(JSON_DELIMITER_VALUE, JSON_DELIMITER_SPACE, key_end, remain_len);
if (!value_begin) {
return -1;
}
_increase_pos(&value_begin, remain_len);
// filter all the space
while (*value_begin == ' ') {
value_begin++;
(*remain_len)--;
if (*remain_len <= 0) {
return -1;
}
};
JsonElementType type;
char *value_end = NULL;
switch (*value_begin) {
case JSON_DELIMITER_ARRAY_BEGIN:
// should + 1 for escape first [
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_ARRAY;
break;
case JSON_DELIMITER_OBJECT_BEGIN:
// should + 1 for escape first {
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_OBJECT;
break;
case JSON_DELIMITER_TYPE_STRING:
// should + 1 for escape first "
_increase_pos(&value_begin, remain_len);
type = JSON_ELEMENT_VALUE_STRING;
break;
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_UPPER:
case JSON_DELIMITER_TYPE_BOOLEAN_TRUE_LOWER:
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_UPPER:
case JSON_DELIMITER_TYPE_BOOLEAN_FALSE_LOWER:
type = JSON_ELEMENT_VALUE_BOOLEAN;
break;
case JSON_DELIMITER_TYPE_NULL_UPPER:
case JSON_DELIMITER_TYPE_NULL_LOWER:
type = JSON_ELEMENT_VALUE_NULL;
break;
default:
type = JSON_ELEMENT_VALUE_NUMBER;
break;
}
value_end = _find_json_value_element_end(sg_element_matched_func[type].is_begin_matched,
sg_element_matched_func[type].is_end_matched, value_begin, remain_len);
if (!value_end) {
return -1;
}
int is_object_or_array = (type == JSON_ELEMENT_ARRAY || type == JSON_ELEMENT_OBJECT);
int is_object_or_array_or_string = (is_object_or_array || type == JSON_ELEMENT_VALUE_STRING);
value->type = type;
value->pos_begin = value_begin - is_object_or_array; // include '[' or '{'
value->element_len = value_end - value->pos_begin + is_object_or_array; // include ']' or '}'
value->pos_end = value_end + is_object_or_array_or_string; // filter '"' , ']' or '}'
return 0;
}
/**
* @brief Get value by key from json string
*
* @param[in] str json string
* @param[in] str_len strign length
* @param[in] key key
* @param[in] key_len key length
* @param[out] value value
* @return 0 for success
*/
int json_get_value_by_key(const char *str, int str_len, const char *key, int key_len, json_value *value)
{
int rc = 0;
char *object_begin = NULL;
json_key key_found = {JSON_ELEMENT_KEY, 0, 0, 0};
object_begin = _find_json_delimiter(JSON_DELIMITER_OBJECT_BEGIN, JSON_DELIMITER_SPACE, (char *)str, &str_len);
if (!object_begin) {
return -1;
}
_increase_pos(&object_begin, &str_len);
do {
rc = _get_json_key(object_begin, &str_len, &key_found);
if (rc) {
break;
}
_increase_pos(&key_found.pos_end, &str_len);
rc = _get_json_value(key_found.pos_end, &str_len, value);
if (rc) {
break;
}
// NULL of object begin can be ok for reach the end of str
object_begin = _find_json_delimiter(JSON_DELIMITER_ELEMENT_END, JSON_DELIMITER_SPACE, value->pos_end, &str_len);
if (object_begin) {
_increase_pos(&object_begin, &str_len);
}
} while (key_len != key_found.element_len || strncmp(key, key_found.pos_begin, key_found.element_len));
return rc;
}
/**
* @brief Get value from json string. Not strict, just for iot scene, we suppose all the string is valid json.
*
* @param[in] key key in json, support nesting with '.'
* @param[in] key_len key len
* @param[in] src json string
* @param[in] src_len src length
* @param[out] value value
* @return 0 for success
*/
int utils_json_value_get(const char *key, int key_len, const char *src, int src_len, UtilsJsonValue *value)
{
int rc = 0;
char *delim = NULL;
char *src_iter = (char *)src;
int src_iter_len = src_len;
char *key_iter = (char *)key;
char *key_next = NULL;
int key_next_len = 0;
json_value value_tmp;
// key can be separated by '.', such as: outer_key.(.......).inner_key
while ((delim = strchr(key_iter, '.'))) {
key_next = key_iter;
key_next_len = delim - key_iter;
rc = json_get_value_by_key(src_iter, src_iter_len, key_next, key_next_len, &value_tmp);
if (rc) {
return rc;
}
src_iter = value_tmp.pos_begin;
src_iter_len = value_tmp.element_len;
key_iter = delim + 1;
}
// found inner key and get value
rc = json_get_value_by_key(src_iter, src_iter_len, key_iter, key_len + key - key_iter, &value_tmp);
if (rc) {
return rc;
}
value->value = value_tmp.pos_begin;
value->value_len = value_tmp.element_len;
return 0;
}
/**
* @brief Get data of value with type.
*
* @param[in] value @see UtilsJsonValue
* @param[in] type value type, string can use value directly. @see UtilsJsonValueType
* @param[out] data data pointer, user should
* @return 0 for success
*/
int utils_json_value_data_get(UtilsJsonValue value, UtilsJsonValueType type, void *data)
{
char value_tmp[32] = {0};
if (value.value_len > sizeof(value_tmp)) {
return -1;
}
strncpy(value_tmp, value.value, value.value_len);
switch (type) {
case UTILS_JSON_VALUE_TYPE_INT32:
return !(sscanf(value_tmp, "%" SCNi32, (int32_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_INT64:
return !(sscanf(value_tmp, "%" SCNi64, (int64_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_UINT32:
return !(sscanf(value_tmp, "%" SCNu32, (uint32_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_UINT64:
return !(sscanf(value_tmp, "%" SCNu64, (uint64_t *)data) == 1);
case UTILS_JSON_VALUE_TYPE_FLOAT:
return !(sscanf(value_tmp, "%f", (float *)data) == 1);
case UTILS_JSON_VALUE_TYPE_DOUBLE:
return !(sscanf(value_tmp, "%lf", (double *)data) == 1);
case UTILS_JSON_VALUE_TYPE_BOOLEAN:
*(int *)data = strcmp(value_tmp, "false");
return 0;
default:
break;
}
return -1;
}
/**
* @brief Return unsigned int value of key in json.
*
* @return 0 for success
*/
int utils_json_get_uint32(const char *key, int key_len, const char *src, int src_len, uint32_t *data)
{
int rc;
UtilsJsonValue tmp;
rc = utils_json_value_get(key, key_len, src, src_len, &tmp);
if (rc) {
return -1;
}
rc = utils_json_value_data_get(tmp, UTILS_JSON_VALUE_TYPE_UINT32, data);
if (rc) {
return -1;
}
return 0;
}
/**
* @brief Remove '\\' in json string.
*
* @param[in,out] src string to transfer
* @param[in] src_len string len
* @return length after transfer
*/
int utils_json_strip_transfer(char *src, int src_len)
{
char *src_tmp = src;
char *end = src + src_len;
while (src_tmp < end) {
if (*src_tmp == '\\') {
memmove(src_tmp, src_tmp + 1, end - src_tmp);
end--;
}
src_tmp++;
}
return end - src;
}

View File

@@ -0,0 +1,326 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_list.c
* @brief utils list operation
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-25
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_list.h"
/**
* @brief Define list node.
*
*/
typedef struct ListNode {
struct ListNode *prev;
struct ListNode *next;
void * val;
} ListNode;
/**
* @brief Double Linked List.
*
*/
typedef struct {
UtilsListFunc func;
ListNode * head;
ListNode * tail;
void * lock;
int len;
int max_len;
} List;
/**
* @brief List iterator.
*
*/
typedef struct {
List * list;
ListNode * next;
UtilsListDirection direction;
} ListIterator;
/**
* @brief Lock list.
*
* @param[in] list pointer to list
*/
static inline void _list_lock(List *list)
{
if (list->lock) {
list->func.list_lock(list->lock);
}
}
/**
* @brief Unlock list.
*
* @param[in] list pointer to list
*/
static inline void _list_unlock(List *list)
{
if (list->lock) {
list->func.list_unlock(list->lock);
}
}
/**
* @brief Delete the node in list and release the resource.
*
* @param[in] list pointer to list
* @param[in] node pointer to node needed remove
*/
static void _list_remove(void *list, void *node)
{
List * self = (List *)list;
ListNode *list_node = (ListNode *)node;
list_node->prev ? (list_node->prev->next = list_node->next) : (self->head = list_node->next);
list_node->next ? (list_node->next->prev = list_node->prev) : (self->tail = list_node->prev);
self->func.list_free(list_node->val);
self->func.list_free(list_node);
if (self->len) {
--self->len;
}
}
/**
* @brief Create list with max len, return NULL if fail.
*
* @param[in] func function needed by list
* @param[in] max_len max_len of list
* @return pointer to list, NULL for failed
*/
void *utils_list_create(UtilsListFunc func, int max_len)
{
List *self;
if (max_len <= 0) {
return NULL;
}
self = (List *)func.list_malloc(sizeof(List));
if (!self) {
return NULL;
}
memset(self, 0, sizeof(List));
if (func.list_lock_init) {
self->lock = func.list_lock_init();
if (!self->lock) {
func.list_free(self);
return NULL;
}
}
self->func = func;
self->max_len = max_len;
return self;
}
/**
* @brief Destroy list.
*
* @param[in] list pointer to list
*/
void utils_list_destroy(void *list)
{
if (!list) {
return;
}
List *self = (List *)list;
uint32_t len = self->len;
ListNode *next;
ListNode *curr = self->head;
while (len--) {
next = curr->next;
self->func.list_free(curr->val);
self->func.list_free(curr);
curr = next;
}
if (self->lock) {
self->func.list_lock_deinit(self->lock);
}
self->func.list_free(self);
}
/**
* @brief Get list len.
*
* @param[in] list pointer to list
* @return len of list
*/
int utils_list_len_get(void *list)
{
List *self = (List *)list;
return self->len;
}
/**
* @brief Push the node to list tail, return NULL if node invalid.
*
* @param[in] list pointer to list
* @param[in] val value needed to push to list
* @return pointer to node, NULL for failed
*/
void *utils_list_push(void *list, void *val)
{
List *self = (List *)list;
_list_lock(self);
if (!val || self->len >= self->max_len) {
_list_unlock(self);
return NULL;
}
ListNode *node;
node = self->func.list_malloc(sizeof(ListNode));
if (!node) {
_list_unlock(self);
return NULL;
}
node->prev = NULL;
node->next = NULL;
node->val = val;
if (self->len) {
node->prev = self->tail;
node->next = NULL;
self->tail->next = node;
self->tail = node;
} else {
self->head = self->tail = node;
node->prev = node->next = NULL;
}
++self->len;
_list_unlock(self);
return node;
}
/**
* @brief Pop the value from list head, return NULL if list empty.
*
* @param[in] list pointer to list
* @return value in the head node
*/
void *utils_list_pop(void *list)
{
List * self = (List *)list;
ListNode *node = NULL;
_list_lock(self);
if (!self->len) {
_list_unlock(self);
return NULL;
}
node = self->head;
if (--self->len) {
(self->head = node->next)->prev = NULL;
} else {
self->head = self->tail = NULL;
}
node->next = node->prev = NULL;
_list_unlock(self);
void *val = node->val;
self->func.list_free(node);
return val;
}
/**
* @brief Delete the node in list and release the resource.
*
* @param[in] list pointer to list
* @param[in] node pointer to node needed remove
*/
void utils_list_remove(void *list, void *node)
{
List *self = (List *)list;
_list_lock(self);
_list_remove(self, node);
_list_unlock(self);
}
/**
* @brief Process list using handle function.
*
* @param[in] list pointer to list
* @param[in] direction direction to traverse
* @param[in] handle process function @see OnNodeProcessHandle
* @param[in,out] usr_data usr data to pass to OnNodeProcessHandle
*/
void utils_list_process(void *list, uint8_t direction, OnNodeProcessHandle handle, void *usr_data)
{
int rc;
ListNode *node = NULL;
List * self = (List *)list;
_list_lock(self);
if (!utils_list_len_get(list)) {
_list_unlock(self);
return;
}
ListIterator iterator = {
.direction = direction,
.list = self,
.next = direction == LIST_HEAD ? self->head : self->tail,
};
// traverse list to process
while ((node = iterator.next)) {
iterator.next = iterator.direction == LIST_HEAD ? node->next : node->prev;
if (!node->val) {
_list_remove(list, node);
continue;
}
// process node and val
if (handle) {
rc = handle(list, node, node->val, usr_data);
if (rc) {
break;
}
}
}
_list_unlock(list);
}

View File

@@ -0,0 +1,178 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file utils_log.c
* @brief different level log generator
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-05-28
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-05-28 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "utils_log.h"
static const char *LEVEL_STR[] = {"DIS", "ERR", "WRN", "INF", "DBG"};
static LogHandleFunc sg_log_handle_func;
static char *sg_log_buffer;
static int sg_log_max_size;
static void *sg_log_mutex;
static LogLevel sg_log_print_level = LOG_LEVEL_DEBUG;
extern LogLevel sg_log_upload_level;
/**
* @brief Get file name form path.
*
* @param[in] path file path
* @return file name
*/
static const char *_get_filename(const char *path)
{
#ifdef WIN32
char ch = '\\';
#else
char ch = '/';
#endif
const char *q = strrchr(path, ch);
if (!q) {
q = path;
} else {
q++;
}
return q;
}
/**
* @brief Init log with func, log level, max log size.
*
* @param[in] func function should be implement for utils log
* @param[in] log_level @see LogLevel
* @param[in] max_log_size max size of log to print
* @return 0 for success
*/
int utils_log_init(LogHandleFunc func, LogLevel log_level, int max_log_size)
{
sg_log_handle_func = func;
sg_log_print_level = log_level;
sg_log_max_size = max_log_size;
if (func.log_mutex_create) {
sg_log_mutex = func.log_mutex_create();
if (!sg_log_mutex) {
return -1;
}
}
if (func.log_malloc) {
sg_log_buffer = func.log_malloc(max_log_size);
if (!sg_log_buffer) {
if (sg_log_mutex) {
func.log_mutex_destroy(sg_log_mutex);
}
}
}
return !sg_log_buffer;
}
/**
* @brief Deinit log.
*
*/
void utils_log_deinit(void)
{
sg_log_handle_func.log_free(sg_log_buffer);
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_destroy(sg_log_mutex);
}
sg_log_mutex = NULL;
sg_log_buffer = NULL;
}
/**
* @brief Set log level.
*
* @param log_level @see LogLevel
*/
void utils_log_set_level(LogLevel log_level)
{
sg_log_print_level = log_level;
}
/**
* @brief Get log level.
*
* @return @see LogLevel
*/
LogLevel utils_log_get_level(void)
{
return sg_log_print_level;
}
/**
* @brief Generate log if level higher than set.
*
* @param[in] file file path
* @param[in] func function where generate log
* @param[in] line line of source file where genertate log
* @param[in] level @see LogLevel
* @param[in] fmt format of log content
*/
void utils_log_gen(const char *file, const char *func, const int line, const int level, const char *fmt, ...)
{
if (level > sg_log_print_level) {
return;
}
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_lock(sg_log_mutex);
}
/* format log content */
const char *file_name = _get_filename(file);
char *o = sg_log_buffer;
memset(sg_log_buffer, 0, sg_log_max_size);
o += snprintf(sg_log_buffer, sg_log_max_size, "%s|%s|%s|%s(%d): ", LEVEL_STR[level],
sg_log_handle_func.log_get_current_time_str(), file_name, func, line);
va_list ap;
va_start(ap, fmt);
vsnprintf(o, sg_log_max_size - 2 - strlen(sg_log_buffer), fmt, ap);
va_end(ap);
strncat(sg_log_buffer, "\r\n", sg_log_max_size - strlen(sg_log_buffer) - 1);
if (level <= sg_log_print_level) {
if (sg_log_handle_func.log_handle) {
sg_log_handle_func.log_handle(sg_log_buffer);
}
sg_log_handle_func.log_printf("%s", sg_log_buffer);
}
/* append to upload buffer */
if (sg_log_handle_func.log_upload) {
sg_log_handle_func.log_upload(level, sg_log_buffer);
}
if (sg_log_mutex) {
sg_log_handle_func.log_mutex_unlock(sg_log_mutex);
}
return;
}

View File

@@ -0,0 +1,8 @@
Language: Cpp
BasedOnStyle: Google
ColumnLimit: 120
DerivePointerAlignment: true
PointerAlignment: Left
SortIncludes: true
IncludeBlocks: Preserve
IndentPPDirectives: AfterHash

View File

@@ -0,0 +1,181 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2021 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file test_utils.cc
* @brief unittest for utils
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2021-07-07
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-07-07 <td>1.0 <td>fancyxu <td>first commit
* <tr><td>2021-07-27 <td>1.1 <td>fancyxu <td>support utils json
* <tr><td>2021-07-29 <td>1.1 <td>fancyxu <td>rename HAL_Timer and add utils json test
* </table>
*/
#include <iostream>
#include <string>
#include "gtest/gtest.h"
#include "qcloud_iot_platform.h"
#include "utils_json.h"
#include "utils_list.h"
#include "utils_log.h"
namespace utils_unittest {
/**
* @brief test fixture of utils list
*
*/
class UtilsListTest : public testing::Test {
protected:
void SetUp() override {
UtilsListFunc func = {
.list_malloc = HAL_Malloc,
.list_free = HAL_Free,
.list_lock_init = HAL_MutexCreate,
.list_lock = HAL_MutexLock,
.list_unlock = HAL_MutexUnlock,
.list_lock_deinit = HAL_MutexDestroy,
};
self_list = utils_list_create(func, 10);
ASSERT_NE(self_list, nullptr);
for (int i = 0; i < 10;) {
int *val = reinterpret_cast<int *>(HAL_Malloc(sizeof(int)));
*val = i++;
ASSERT_NE(utils_list_push(self_list, reinterpret_cast<void *>(val)), nullptr);
ASSERT_EQ(utils_list_len_get(self_list), i);
}
}
void TearDown() override { utils_list_destroy(self_list); }
void *self_list;
};
/**
* @brief Test list.
*
*/
TEST_F(UtilsListTest, list) {
ASSERT_EQ(utils_list_push(self_list, reinterpret_cast<void *>(1)), nullptr);
for (int i = 0; i < 10; i++) {
ASSERT_EQ(utils_list_len_get(self_list), 10 - i);
int *val = reinterpret_cast<int *>(utils_list_pop(self_list));
ASSERT_EQ(*val, i);
HAL_Free(val);
}
}
/**
* @brief Test remove list node
*
* @param[in,out] list pointer to list
* @param[in,out] node pointer to node
* @param[in,out] val pointer to val
* @param[in,out] usr_data pointer to usr data
* @return @see UtilsListResult
*/
static UtilsListResult list_process_remove(void *list, void *node, void *val, void *usr_data) {
static int i = 0;
if (*reinterpret_cast<int *>(val) != i++) {
return LIST_TRAVERSE_BREAK;
}
utils_list_remove(list, node);
return LIST_TRAVERSE_CONTINUE;
}
/**
* @brief Test list process.
*
*/
TEST_F(UtilsListTest, list_process) {
utils_list_process(self_list, LIST_HEAD, list_process_remove, NULL);
ASSERT_EQ(utils_list_len_get(self_list), 0);
}
/**
* @brief Test log.
*
*/
TEST(UtilsLogTest, log) {
LogHandleFunc func = {0};
func.log_malloc = HAL_Malloc;
func.log_free = HAL_Free;
func.log_get_current_time_str = HAL_Timer_Current;
func.log_printf = HAL_Printf;
ASSERT_EQ(utils_log_init(func, LOG_LEVEL_DEBUG, 2048), 0);
Log_d("Here is a debug level log test!");
Log_i("Here is a info level log test!");
Log_w("Here is a warning level log test!");
Log_e("Here is a error level log test!");
utils_log_deinit();
}
/**
* @brief Test json.
*
*/
TEST(UtilsJsonTest, json) {
char test_json[] =
"{\"str_test\":\"test\",\"int_test\":100,\"float_test\":1.210f,\"bool_test\":true,"
"\"bool_false_test\":false,\"null_test\":null}";
UtilsJsonValue value;
int data_int = 0;
ASSERT_EQ(utils_json_value_get("int_test", strlen("int_test"), test_json, strlen(test_json), &value), 0);
ASSERT_EQ(utils_json_value_data_get(value, UTILS_JSON_VALUE_TYPE_INT32, &data_int), 0);
ASSERT_EQ(data_int, 100);
float data_float = 0.0;
ASSERT_EQ(utils_json_value_get("float_test", strlen("float_test"), test_json, strlen(test_json), &value), 0);
ASSERT_EQ(utils_json_value_data_get(value, UTILS_JSON_VALUE_TYPE_FLOAT, &data_float), 0);
ASSERT_EQ(data_float, 1.210f);
ASSERT_EQ(utils_json_value_get("bool_test", strlen("bool_test"), test_json, strlen(test_json), &value), 0);
ASSERT_EQ(strncmp(value.value, "true", value.value_len), 0);
ASSERT_EQ(utils_json_value_get("bool_false_test", strlen("bool_false_test"), test_json, strlen(test_json), &value),
0);
ASSERT_EQ(strncmp(value.value, "false", value.value_len), 0);
ASSERT_EQ(utils_json_value_get("null_test", strlen("null_test"), test_json, strlen(test_json), &value), 0);
ASSERT_EQ(strncmp(value.value, "null", value.value_len), 0);
ASSERT_EQ(utils_json_value_get("str_test", strlen("str_test"), test_json, strlen(test_json), &value), 0);
ASSERT_EQ(strncmp(value.value, "test", value.value_len), 0);
char test_json_depth[] = "{\"depth_test\": {\"test\":\"test1\"}}";
ASSERT_EQ(utils_json_value_get("depth_test.test", strlen("depth_test.test"), test_json_depth, strlen(test_json_depth),
&value),
0);
ASSERT_EQ(strncmp(value.value, "test1", value.value_len), 0);
char test_json_before_strip[] =
"{\\\"str_test\":\\\"test\\\",\\\"int_test\\\":100,\\\"float_test\\\":1.210f,\\\"bool_test\\\":true,"
"\\\"bool_false_test\\\":false,\\\"null_test\\\":null}";
ASSERT_EQ(utils_json_strip_transfer(test_json_before_strip, strlen(test_json_before_strip)), strlen(test_json));
ASSERT_EQ(strncmp(test_json_before_strip, test_json, strlen(test_json_before_strip)), 0);
}
} // namespace utils_unittest