#include "CppUTest/TestHarness.h" #include "CppUTest/CommandLineTestRunner.h" #include "CppUTestExt/MockSupport.h" #include "classic/obex.h" #include "classic/obex_parser.h" #include "classic/obex_message_builder.h" #include "btstack_util.h" static const uint8_t flags = 1 << 1; static const uint16_t maximum_obex_packet_length = 0xFFFF; static const uint8_t obex_version_number = OBEX_VERSION; static const uint8_t target[] = { 1, 2, 3, 4}; // from parser_callback static uint8_t test_header_id; static uint8_t test_header_buffer[100]; static uint16_t test_header_len; // mock hci_dump.c extern "C" void hci_dump_log(int log_level, const char * format, ...){} static void parser_callback(void * user_data, uint8_t header_id, uint16_t total_len, uint16_t data_offset, const uint8_t * data_buffer, uint16_t data_len){ if (obex_parser_header_store(test_header_buffer, sizeof(test_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_PARSER_HEADER_COMPLETE){ test_header_len = total_len; test_header_id = header_id; } } TEST_GROUP(OBEX_PARSER){ obex_parser_t parser; uint8_t message[300]; void setup(void){ test_header_id = 0; test_header_len = 0; } void teardown(void){ } void parse_request(void){ obex_parser_init_for_request(&parser, &parser_callback, NULL); uint16_t message_len = big_endian_read_16(message, 1); for (uint16_t i = 0; i < message_len - 1;i++){ obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[i], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_INCOMPLETE, parser_state); } obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[message_len-1], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_COMPLETE, parser_state); } void parse_response(uint8_t opcode){ obex_parser_init_for_response(&parser, opcode, &parser_callback, NULL); uint16_t message_len = big_endian_read_16(message, 1); for (uint16_t i = 0; i < message_len - 1;i++){ obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[i], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_INCOMPLETE, parser_state); } obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[message_len-1], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_COMPLETE, parser_state); } }; TEST(OBEX_PARSER, RequestOverrun){ (void) obex_message_builder_request_create_connect(message, sizeof(message), obex_version_number, flags, maximum_obex_packet_length); uint16_t message_len = big_endian_read_16(message, 1); for (uint16_t i = 0; i < message_len - 1;i++){ obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[i], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_INCOMPLETE, parser_state); } obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[message_len-1], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_COMPLETE, parser_state); parser_state = obex_parser_process_data(&parser, &message[message_len], 1); CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_OVERRUN, parser_state); } TEST(OBEX_PARSER, RequestInvalid){ (void) obex_message_builder_request_create_connect(message, sizeof(message), obex_version_number, flags, maximum_obex_packet_length); // decrease packet len uint16_t message_len = big_endian_read_16(message, 1) - 1; big_endian_store_16(message, 1, message_len); for (uint16_t i = 0; i < message_len;i++){ obex_parser_object_state_t parser_state = obex_parser_process_data(&parser, &message[i], 1); if (i < 2){ CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_INCOMPLETE, parser_state); } else { CHECK_EQUAL(OBEX_PARSER_OBJECT_STATE_INVALID, parser_state); } } } TEST(OBEX_PARSER, ConnectRequest){ (void) obex_message_builder_request_create_connect(message, sizeof(message), obex_version_number, flags, maximum_obex_packet_length); parse_request(); obex_parser_operation_info_t op_info; obex_parser_get_operation_info(&parser, &op_info); CHECK_EQUAL(OBEX_OPCODE_CONNECT, op_info.opcode); CHECK_EQUAL(obex_version_number, op_info.obex_version_number); CHECK_EQUAL(flags, op_info.flags); CHECK_EQUAL(maximum_obex_packet_length, op_info.max_packet_length); } TEST(OBEX_PARSER, ConnectRequestWithTarget){ (void) obex_message_builder_request_create_connect(message, sizeof(message), obex_version_number, flags, maximum_obex_packet_length); (void) obex_message_builder_header_add_target(message, sizeof(message), target, sizeof(target)); parse_request(); obex_parser_operation_info_t op_info; obex_parser_get_operation_info(&parser, &op_info); CHECK_EQUAL(OBEX_HEADER_TARGET, test_header_id); CHECK_EQUAL(sizeof(target), test_header_len); MEMCMP_EQUAL(target, test_header_buffer, sizeof(target)); } TEST(OBEX_PARSER, ConnectResponse){ // no create response yet, fake it (void) obex_message_builder_request_create_connect(message, sizeof(message), obex_version_number, flags, maximum_obex_packet_length); message[0] = OBEX_RESP_SUCCESS; parse_response(OBEX_OPCODE_CONNECT); obex_parser_operation_info_t op_info; obex_parser_get_operation_info(&parser, &op_info); CHECK_EQUAL(OBEX_RESP_SUCCESS, op_info.response_code); CHECK_EQUAL(obex_version_number, op_info.obex_version_number); CHECK_EQUAL(flags, op_info.flags); CHECK_EQUAL(maximum_obex_packet_length, op_info.max_packet_length); } TEST(OBEX_PARSER, GetResponseWithSRM){ // no get response yet, fake it (void) obex_message_builder_request_create_get(message, sizeof(message), 0x1234); obex_message_builder_header_add_srm_enable(message, sizeof(message)); parse_request(); obex_parser_operation_info_t op_info; obex_parser_get_operation_info(&parser, &op_info); } TEST(OBEX_PARSER, SetPathResponse){ const uint8_t set_path_response_success[] = { 0xa0, 0x00, 0x03}; memcpy(message, set_path_response_success, sizeof(set_path_response_success)); parse_response(OBEX_OPCODE_SETPATH); } /** App Param Parser */ static uint8_t test_tag_id; static uint8_t test_tag_buffer[100]; static uint16_t test_tag_len; void app_param_parser_callback(void * user_data, uint8_t tag_id, uint8_t total_len, uint8_t data_offset, const uint8_t * data_buffer, uint8_t data_len){ if (obex_app_param_parser_tag_store(test_header_buffer, sizeof(test_header_buffer), total_len, data_offset, data_buffer, data_len) == OBEX_APP_PARAM_PARSER_TAG_COMPLETE){ test_tag_len = total_len; test_tag_id = tag_id; } } TEST_GROUP(APP_PARAM_PARSER){ obex_app_param_parser_t parser; void setup(void){ test_tag_id = 0; test_tag_len = 0; } void teardown(void){ } void parse_app_params(const uint8_t * app_params, uint8_t param_len){ obex_app_param_parser_init(&parser, &app_param_parser_callback, param_len, NULL); for (int i = 0; i < param_len - 1;i++){ obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &app_params[i], 1); CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE, parser_state); } if (param_len > 0){ obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &app_params[param_len-1], 1); CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_COMPLETE, parser_state); } } }; TEST(APP_PARAM_PARSER, EmptyParams){ parse_app_params(NULL, 0); CHECK_EQUAL(0, test_tag_id); CHECK_EQUAL(0, test_tag_len); } TEST(APP_PARAM_PARSER, SingleParam){ uint8_t message[] = { 0x01, 0x02, 0x03, 0x4}; parse_app_params(message, sizeof(message)); CHECK_EQUAL(1, test_tag_id); CHECK_EQUAL(2, test_tag_len); } TEST(APP_PARAM_PARSER, Overrun){ uint8_t message[] = { 0x01, 0x02, 0x03, 0x4}; parse_app_params(message, sizeof(message)); obex_app_param_parser_params_state_t parser_state = obex_app_param_parser_process_data(&parser, &message[0], 1); CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_OVERRUN, parser_state); CHECK_EQUAL(1, test_tag_id); CHECK_EQUAL(2, test_tag_len); } TEST(APP_PARAM_PARSER, InvalidTagLen){ uint8_t message[] = { 0x01, 0x04, 0x03, 0x4}; obex_app_param_parser_t parser; obex_app_param_parser_init(&parser, &app_param_parser_callback, sizeof(message), NULL); obex_app_param_parser_params_state_t parser_state; parser_state = obex_app_param_parser_process_data(&parser, &message[0], 1); CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INCOMPLETE, parser_state); parser_state = obex_app_param_parser_process_data(&parser, &message[1], 1); CHECK_EQUAL(OBEX_APP_PARAM_PARSER_PARAMS_STATE_INVALID, parser_state); CHECK_EQUAL(0, test_tag_id); CHECK_EQUAL(0, test_tag_len); } int main (int argc, const char * argv[]){ return CommandLineTestRunner::RunAllTests(argc, argv); }