/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4232) /* function pointer to dll symbol */ #endif enum { S_BUFFER_SIZE = 128 }; struct packet_test_fixture; /* Function type used to init and cleanup a fixture */ typedef int(packet_init_fn)(struct packet_test_fixture *); /* Function used to encode a packet (this should be set to a function from packets.h) */ typedef int(packet_encode_fn)(struct aws_byte_buf *, void *); /* Function used to decode a packet (this should be set to a function from packets.h) */ typedef int(packet_decode_fn)(struct aws_byte_cursor *, void *); /* Function used to check if two packets are equal */ typedef bool(packet_eq_fn)(void *, void *, size_t); /* Helper for comparing the fixed headers of packets */ static bool s_fixed_header_eq(struct aws_mqtt_fixed_header *l, struct aws_mqtt_fixed_header *r) { return l->packet_type == r->packet_type && l->flags == r->flags && l->remaining_length == r->remaining_length; } /* Default packet compare function, checks headers then memcmps the rest */ static bool s_packet_eq_default(void *a, void *b, size_t size) { static const size_t HEADER_SIZE = sizeof(struct aws_mqtt_fixed_header); return s_fixed_header_eq(a, b) && memcmp((uint8_t *)a + HEADER_SIZE, (uint8_t *)b + HEADER_SIZE, size - HEADER_SIZE) == 0; } /* Contains all of the information required to run a packet's test case */ struct packet_test_fixture { enum aws_mqtt_packet_type type; size_t size; packet_init_fn *init; packet_encode_fn *encode; packet_decode_fn *decode; packet_init_fn *teardown; packet_eq_fn *equal; struct aws_allocator *allocator; void *in_packet; void *out_packet; struct aws_byte_buf buffer; }; static int s_packet_test_before(struct aws_allocator *allocator, void *ctx) { struct packet_test_fixture *fixture = ctx; fixture->allocator = allocator; /* Setup the fixture */ fixture->in_packet = aws_mem_acquire(allocator, fixture->size); ASSERT_NOT_NULL(fixture->in_packet); memset(fixture->in_packet, 0, fixture->size); fixture->out_packet = aws_mem_acquire(allocator, fixture->size); ASSERT_NOT_NULL(fixture->out_packet); memset(fixture->out_packet, 0, fixture->size); return AWS_OP_SUCCESS; } static int s_packet_test_run(struct aws_allocator *allocator, void *ctx) { struct packet_test_fixture *fixture = ctx; aws_byte_buf_init(&fixture->buffer, allocator, S_BUFFER_SIZE); /* Init the in_packet & buffer */ ASSERT_SUCCESS(fixture->init(fixture)); /* Encode */ /* Create the output buffer */ struct aws_byte_buf output_buffer; ASSERT_SUCCESS(aws_byte_buf_init(&output_buffer, allocator, S_BUFFER_SIZE)); /* Encode the packet */ ASSERT_SUCCESS(fixture->encode(&output_buffer, fixture->in_packet)); /* Compare the buffers */ ASSERT_BIN_ARRAYS_EQUALS(fixture->buffer.buffer, fixture->buffer.len, output_buffer.buffer, output_buffer.len); aws_byte_buf_clean_up(&output_buffer); /* Decode */ /* Decode the buffer */ struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(&fixture->buffer); ASSERT_SUCCESS(fixture->decode(&cursor, fixture->out_packet)); /* Compare the packets */ if (fixture->equal) { ASSERT_TRUE(fixture->equal(fixture->out_packet, fixture->in_packet, fixture->size)); } else { ASSERT_TRUE(s_packet_eq_default(fixture->out_packet, fixture->in_packet, fixture->size)); } return AWS_OP_SUCCESS; } static int s_packet_test_after(struct aws_allocator *allocator, int setup_result, void *ctx) { (void)setup_result; struct packet_test_fixture *fixture = ctx; /* Tear down the packet & buffer */ if (fixture->teardown) { fixture->teardown(fixture); } /* Tear down the fixture */ aws_mem_release(allocator, fixture->in_packet); aws_mem_release(allocator, fixture->out_packet); aws_byte_buf_clean_up(&fixture->buffer); return AWS_OP_SUCCESS; } #define PACKET_TEST_NAME(e_type, t_name, s_name, i, t, e) \ static struct packet_test_fixture mqtt_packet_##t_name##_fixture = { \ .type = AWS_MQTT_PACKET_##e_type, \ .size = sizeof(struct aws_mqtt_packet_##s_name), \ .init = (i), \ .encode = (packet_encode_fn *)&aws_mqtt_packet_##s_name##_encode, \ .decode = (packet_decode_fn *)&aws_mqtt_packet_##s_name##_decode, \ .teardown = (t), \ .equal = (e), \ }; \ AWS_TEST_CASE_FIXTURE( \ mqtt_packet_##t_name, \ s_packet_test_before, \ s_packet_test_run, \ s_packet_test_after, \ &mqtt_packet_##t_name##_fixture) #define PACKET_TEST(e_type, s_name, i, t, e) PACKET_TEST_NAME(e_type, s_name, s_name, i, t, e) static uint8_t s_client_id[] = "Test Client ID"; enum { CLIENT_ID_LEN = sizeof(s_client_id) }; static uint8_t s_topic_name[] = "test/topic"; enum { TOPIC_NAME_LEN = sizeof(s_topic_name) }; static uint8_t s_payload[] = "This s_payload contains data. It is some good ol' fashioned data."; enum { PAYLOAD_LEN = sizeof(s_payload) }; static uint8_t s_username[] = "admin"; enum { USERNAME_LEN = sizeof(s_username) }; static uint8_t s_password[] = "12345"; enum { PASSWORD_LEN = sizeof(s_password) }; /*****************************************************************************/ /* Ack */ static int s_test_ack_init(struct packet_test_fixture *fixture) { /* Init buffer */ uint8_t packet_id = (uint8_t)(fixture->type + 7); /* clang-format off */ uint8_t header[] = { (uint8_t)(fixture->type << 4), /* Packet type */ 2, /* Remaining length */ 0, packet_id, /* Packet identifier */ }; /* Init packet */ switch (fixture->type) { case AWS_MQTT_PACKET_PUBACK: ASSERT_SUCCESS(aws_mqtt_packet_puback_init(fixture->in_packet, packet_id)); break; case AWS_MQTT_PACKET_PUBREC: ASSERT_SUCCESS(aws_mqtt_packet_pubrec_init(fixture->in_packet, packet_id)); break; case AWS_MQTT_PACKET_PUBREL: ASSERT_SUCCESS(aws_mqtt_packet_pubrel_init(fixture->in_packet, packet_id)); /* if pubrel, bit 1 in flags must be set */ header[0] |= 0x2; break; case AWS_MQTT_PACKET_PUBCOMP: ASSERT_SUCCESS(aws_mqtt_packet_pubcomp_init(fixture->in_packet, packet_id)); break; case AWS_MQTT_PACKET_UNSUBACK: ASSERT_SUCCESS(aws_mqtt_packet_unsuback_init(fixture->in_packet, packet_id)); break; default: AWS_ASSUME(false); break; } aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); return AWS_OP_SUCCESS; } #define PACKET_TEST_ACK(e_type, name) \ PACKET_TEST_NAME(e_type, name, ack, &s_test_ack_init, NULL, NULL) PACKET_TEST_ACK(PUBACK, puback) PACKET_TEST_ACK(PUBREC, pubrec) PACKET_TEST_ACK(PUBREL, pubrel) PACKET_TEST_ACK(PUBCOMP, pubcomp) PACKET_TEST_ACK(UNSUBACK, unsuback) #undef PACKET_TEST_ACK /*****************************************************************************/ /* Connect */ static int s_test_connect_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_connect_init( fixture->in_packet, aws_byte_cursor_from_array(s_client_id, CLIENT_ID_LEN), false, 0)); /* Init buffer */ /* clang-format off */ uint8_t header[] = { AWS_MQTT_PACKET_CONNECT << 4, /* Packet type */ 10 + 2 + CLIENT_ID_LEN, /* Remaining length */ 0, 4, 'M', 'Q', 'T', 'T', /* Protocol name */ 4, /* Protocol level */ 0, /* Connect Flags */ 0, 0, /* Keep alive */ }; /* clang-format on */ aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); aws_byte_buf_write_u8(&fixture->buffer, 0); aws_byte_buf_write_u8(&fixture->buffer, CLIENT_ID_LEN); aws_byte_buf_write(&fixture->buffer, s_client_id, CLIENT_ID_LEN); return AWS_OP_SUCCESS; } static bool s_test_connect_eq(void *a, void *b, size_t size) { (void)size; struct aws_mqtt_packet_connect *l = a; struct aws_mqtt_packet_connect *r = b; return s_fixed_header_eq(&l->fixed_header, &r->fixed_header) && l->clean_session == r->clean_session && l->has_will == r->has_will && l->will_qos == r->will_qos && l->will_retain == r->will_retain && l->has_password == r->has_password && l->has_username == r->has_username && l->keep_alive_timeout == r->keep_alive_timeout && aws_byte_cursor_eq(&l->client_identifier, &r->client_identifier) && aws_byte_cursor_eq(&l->will_topic, &r->will_topic) && aws_byte_cursor_eq(&l->username, &r->username) && aws_byte_cursor_eq(&l->password, &r->password); } PACKET_TEST(CONNECT, connect, &s_test_connect_init, NULL, &s_test_connect_eq) static int s_test_connect_will_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_connect_init( fixture->in_packet, aws_byte_cursor_from_array(s_client_id, CLIENT_ID_LEN), false, 0)); ASSERT_SUCCESS(aws_mqtt_packet_connect_add_will( fixture->in_packet, aws_byte_cursor_from_array(s_topic_name, TOPIC_NAME_LEN), AWS_MQTT_QOS_EXACTLY_ONCE, true /*retain*/, aws_byte_cursor_from_array(s_payload, PAYLOAD_LEN))); /* Init buffer */ /* clang-format off */ uint8_t header[] = { AWS_MQTT_PACKET_CONNECT << 4, /* Packet type */ 10 + (2 + CLIENT_ID_LEN) + (2 + TOPIC_NAME_LEN) + (2 + PAYLOAD_LEN), /* Remaining length */ 0, 4, 'M', 'Q', 'T', 'T', /* Protocol name */ 4, /* Protocol level */ /* Connect Flags: */ (1 << 2) /* Will flag, bit 2 */ | (AWS_MQTT_QOS_EXACTLY_ONCE << 3)/* Will QoS, bits 4-3 */ | (1 << 5), /* Will Retain, bit 5 */ 0, 0, /* Keep alive */ }; /* clang-format on */ aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); /* client identifier */ aws_byte_buf_write_be16(&fixture->buffer, CLIENT_ID_LEN); aws_byte_buf_write(&fixture->buffer, s_client_id, CLIENT_ID_LEN); /* will topic */ aws_byte_buf_write_be16(&fixture->buffer, TOPIC_NAME_LEN); aws_byte_buf_write(&fixture->buffer, s_topic_name, TOPIC_NAME_LEN); /* will payload */ aws_byte_buf_write_be16(&fixture->buffer, PAYLOAD_LEN); aws_byte_buf_write(&fixture->buffer, s_payload, PAYLOAD_LEN); return AWS_OP_SUCCESS; } PACKET_TEST_NAME(CONNECT, connect_will, connect, &s_test_connect_will_init, NULL, &s_test_connect_eq) static int s_test_connect_password_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_connect_init( fixture->in_packet, aws_byte_cursor_from_array(s_client_id, CLIENT_ID_LEN), false, 0xBEEF)); ASSERT_SUCCESS(aws_mqtt_packet_connect_add_credentials( fixture->in_packet, aws_byte_cursor_from_array(s_username, USERNAME_LEN), aws_byte_cursor_from_array(s_password, PASSWORD_LEN))); /* Init buffer */ /* clang-format off */ uint8_t header[] = { AWS_MQTT_PACKET_CONNECT << 4, /* Packet type */ 10 + (2 + CLIENT_ID_LEN) + (2 + USERNAME_LEN) + (2 + PASSWORD_LEN), /* Remaining length */ 0, 4, 'M', 'Q', 'T', 'T', /* Protocol name */ 4, /* Protocol level */ (1 << 7) | (1 << 6), /* Connect Flags: username bit 7, password bit 6 */ 0xBE, 0xEF, /* Keep alive */ }; /* clang-format on */ aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); /* client identifier */ aws_byte_buf_write_be16(&fixture->buffer, CLIENT_ID_LEN); aws_byte_buf_write(&fixture->buffer, s_client_id, CLIENT_ID_LEN); /* username */ aws_byte_buf_write_be16(&fixture->buffer, USERNAME_LEN); aws_byte_buf_write(&fixture->buffer, s_username, USERNAME_LEN); /* password */ aws_byte_buf_write_be16(&fixture->buffer, PASSWORD_LEN); aws_byte_buf_write(&fixture->buffer, s_password, PASSWORD_LEN); return AWS_OP_SUCCESS; } PACKET_TEST_NAME(CONNECT, connect_password, connect, &s_test_connect_password_init, NULL, &s_test_connect_eq) /*****************************************************************************/ /* Connack */ static int s_test_connack_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_connack_init(fixture->in_packet, true, AWS_MQTT_CONNECT_ACCEPTED)); /* Init buffer */ /* clang-format off */ uint8_t header[] = { AWS_MQTT_PACKET_CONNACK << 4, /* Packet type */ 2, /* Remaining length */ 1, /* Acknowledge flags */ AWS_MQTT_CONNECT_ACCEPTED, /* Return code */ }; /* clang-format on */ aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); return AWS_OP_SUCCESS; } PACKET_TEST(CONNACK, connack, &s_test_connack_init, NULL, NULL) /*****************************************************************************/ /* Publish */ static int s_test_publish_qos0_dup_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_publish_init( fixture->in_packet, false /* retain */, AWS_MQTT_QOS_AT_MOST_ONCE, true /* dup */, aws_byte_cursor_from_array(s_topic_name, TOPIC_NAME_LEN), 0, aws_byte_cursor_from_array(s_payload, PAYLOAD_LEN))); /* Init buffer */ /* clang-format off */ aws_byte_buf_write_u8( &fixture->buffer, (AWS_MQTT_PACKET_PUBLISH << 4) /* Packet type bits 7-4 */ | (1 << 3) /* DUP bit 3 */ | (AWS_MQTT_QOS_AT_MOST_ONCE << 1) /* QoS bits 2-1 */ | 0 /* RETAIN bit 0 */); aws_byte_buf_write_u8( &fixture->buffer, 2 + TOPIC_NAME_LEN + PAYLOAD_LEN); /* Remaining length */ aws_byte_buf_write_u8( &fixture->buffer, 0); /* Topic name len byte 1 */ aws_byte_buf_write_u8( &fixture->buffer, TOPIC_NAME_LEN); /* Topic name len byte 2 */ aws_byte_buf_write( &fixture->buffer, s_topic_name, TOPIC_NAME_LEN); /* Topic name */ aws_byte_buf_write( &fixture->buffer, s_payload, PAYLOAD_LEN); /* payload */ /* clang-format on */ return AWS_OP_SUCCESS; } static int s_test_publish_qos2_retain_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_publish_init( fixture->in_packet, true /* retain */, AWS_MQTT_QOS_EXACTLY_ONCE, false /* dup */, aws_byte_cursor_from_array(s_topic_name, TOPIC_NAME_LEN), 7, aws_byte_cursor_from_array(s_payload, PAYLOAD_LEN))); /* Init buffer */ /* clang-format off */ aws_byte_buf_write_u8( &fixture->buffer, (AWS_MQTT_PACKET_PUBLISH << 4) /* Packet type bits 7-4 */ | (0 << 3) /* DUP bit 3 */ | (AWS_MQTT_QOS_EXACTLY_ONCE << 1) /* QoS bits 2-1 */ | 1 /* RETAIN bit 0 */); aws_byte_buf_write_u8( &fixture->buffer, 4 + TOPIC_NAME_LEN + PAYLOAD_LEN); /* Remaining length */ aws_byte_buf_write_u8( &fixture->buffer, 0); /* Topic name len byte 1 */ aws_byte_buf_write_u8( &fixture->buffer, TOPIC_NAME_LEN); /* Topic name len byte 2 */ aws_byte_buf_write( &fixture->buffer, s_topic_name, TOPIC_NAME_LEN); /* Topic name */ aws_byte_buf_write_u8( &fixture->buffer, 0); /* Packet id byte 1 */ aws_byte_buf_write_u8( &fixture->buffer, 7); /* Packet id byte 2 */ aws_byte_buf_write( &fixture->buffer, s_payload, PAYLOAD_LEN); /* payload */ /* clang-format on */ return AWS_OP_SUCCESS; } static bool s_test_publish_eq(void *a, void *b, size_t size) { (void)size; struct aws_mqtt_packet_publish *l = a; struct aws_mqtt_packet_publish *r = b; return s_fixed_header_eq(&l->fixed_header, &r->fixed_header) && l->packet_identifier == r->packet_identifier && aws_byte_cursor_eq(&l->topic_name, &r->topic_name) && aws_byte_cursor_eq(&l->payload, &r->payload); } PACKET_TEST_NAME(PUBLISH, publish_qos0_dup, publish, &s_test_publish_qos0_dup_init, NULL, &s_test_publish_eq) PACKET_TEST_NAME(PUBLISH, publish_qos2_retain, publish, &s_test_publish_qos2_retain_init, NULL, &s_test_publish_eq) /*****************************************************************************/ /* Subscribe */ static int s_test_subscribe_init(struct packet_test_fixture *fixture) { /* Init packets */ ASSERT_SUCCESS(aws_mqtt_packet_subscribe_init(fixture->in_packet, fixture->allocator, 7)); ASSERT_SUCCESS(aws_mqtt_packet_subscribe_init(fixture->out_packet, fixture->allocator, 0)); ASSERT_SUCCESS(aws_mqtt_packet_subscribe_add_topic( fixture->in_packet, aws_byte_cursor_from_array(s_topic_name, TOPIC_NAME_LEN), AWS_MQTT_QOS_EXACTLY_ONCE)); /* Init buffer */ /* clang-format off */ aws_byte_buf_write_u8( &fixture->buffer, (AWS_MQTT_PACKET_SUBSCRIBE << 4) | 0x2); /* Packet type & flags */ aws_byte_buf_write_u8( &fixture->buffer, 4 + TOPIC_NAME_LEN + 1); /* Remaining length */ aws_byte_buf_write_u8( &fixture->buffer, 0); aws_byte_buf_write_u8( &fixture->buffer, 7); aws_byte_buf_write_u8( &fixture->buffer, 0); aws_byte_buf_write_u8( &fixture->buffer, TOPIC_NAME_LEN); aws_byte_buf_write( &fixture->buffer, s_topic_name, TOPIC_NAME_LEN); aws_byte_buf_write_u8( &fixture->buffer, AWS_MQTT_QOS_EXACTLY_ONCE); /* clang-format on */ return AWS_OP_SUCCESS; } static int s_test_subscribe_clean_up(struct packet_test_fixture *fixture) { aws_mqtt_packet_subscribe_clean_up(fixture->in_packet); aws_mqtt_packet_subscribe_clean_up(fixture->out_packet); return AWS_OP_SUCCESS; } static bool s_test_subscribe_eq(void *a, void *b, size_t size) { (void)size; struct aws_mqtt_packet_subscribe *l = a; struct aws_mqtt_packet_subscribe *r = b; if (!s_fixed_header_eq(&l->fixed_header, &r->fixed_header) || l->packet_identifier != r->packet_identifier) { return false; } const size_t length = aws_array_list_length(&l->topic_filters); if (length != aws_array_list_length(&r->topic_filters)) { return false; } for (size_t i = 0; i < length; ++i) { struct aws_mqtt_subscription *lt = NULL; aws_array_list_get_at_ptr(&l->topic_filters, (void **)<, i); struct aws_mqtt_subscription *rt = NULL; aws_array_list_get_at_ptr(&r->topic_filters, (void **)&rt, i); AWS_ASSUME(lt && rt); if (lt->qos != rt->qos) { return false; } if (!aws_byte_cursor_eq(<->topic_filter, &rt->topic_filter)) { return false; } } return true; } PACKET_TEST(SUBSCRIBE, subscribe, &s_test_subscribe_init, &s_test_subscribe_clean_up, &s_test_subscribe_eq) /*****************************************************************************/ /* Suback */ static int s_test_suback_init(struct packet_test_fixture *fixture) { /* Init packets */ ASSERT_SUCCESS(aws_mqtt_packet_suback_init(fixture->in_packet, fixture->allocator, 7)); ASSERT_SUCCESS(aws_mqtt_packet_suback_init(fixture->out_packet, fixture->allocator, 0)); ASSERT_SUCCESS(aws_mqtt_packet_suback_add_return_code(fixture->in_packet, AWS_MQTT_QOS_EXACTLY_ONCE)); ASSERT_SUCCESS(aws_mqtt_packet_suback_add_return_code(fixture->in_packet, AWS_MQTT_QOS_FAILURE)); /* Init buffer */ /* clang-format off */ aws_byte_buf_write_u8( &fixture->buffer, (AWS_MQTT_PACKET_SUBACK << 4) | 0x0); /* Packet type & flags */ aws_byte_buf_write_u8( &fixture->buffer, 2/* variable header */ + 2/* payload */); /* Remaining length */ aws_byte_buf_write_u8( &fixture->buffer, 0); aws_byte_buf_write_u8( &fixture->buffer, 7); aws_byte_buf_write_u8( &fixture->buffer, AWS_MQTT_QOS_EXACTLY_ONCE); /* Payload */ aws_byte_buf_write_u8( &fixture->buffer, AWS_MQTT_QOS_FAILURE); /* Payload */ /* clang-format on */ return AWS_OP_SUCCESS; } static int s_test_suback_clean_up(struct packet_test_fixture *fixture) { aws_mqtt_packet_suback_clean_up(fixture->in_packet); aws_mqtt_packet_suback_clean_up(fixture->out_packet); return AWS_OP_SUCCESS; } static bool s_test_suback_eq(void *a, void *b, size_t size) { (void)size; struct aws_mqtt_packet_suback *l = a; struct aws_mqtt_packet_suback *r = b; if (!s_fixed_header_eq(&l->fixed_header, &r->fixed_header) || l->packet_identifier != r->packet_identifier) { return false; } const size_t length = aws_array_list_length(&l->return_codes); if (length != aws_array_list_length(&r->return_codes)) { return false; } for (size_t i = 0; i < length; ++i) { uint8_t lt = 0; aws_array_list_get_at(&l->return_codes, (void *)<, i); uint8_t rt = 0; aws_array_list_get_at(&r->return_codes, (void *)&rt, i); AWS_ASSUME(lt && rt); } return true; } PACKET_TEST(SUBACK, suback, &s_test_suback_init, &s_test_suback_clean_up, &s_test_suback_eq) /*****************************************************************************/ /* Unsubscribe */ static int s_test_unsubscribe_init(struct packet_test_fixture *fixture) { /* Init packet */ ASSERT_SUCCESS(aws_mqtt_packet_unsubscribe_init(fixture->in_packet, fixture->allocator, 7)); ASSERT_SUCCESS(aws_mqtt_packet_unsubscribe_init(fixture->out_packet, fixture->allocator, 0)); ASSERT_SUCCESS(aws_mqtt_packet_unsubscribe_add_topic( fixture->in_packet, aws_byte_cursor_from_array(s_topic_name, TOPIC_NAME_LEN))); /* Init buffer */ /* clang-format off */ aws_byte_buf_write_u8( &fixture->buffer, (AWS_MQTT_PACKET_UNSUBSCRIBE << 4) | 0x2); /* Packet type & flags */ aws_byte_buf_write_u8( &fixture->buffer, 4 + TOPIC_NAME_LEN); /* Remaining length */ aws_byte_buf_write_u8( &fixture->buffer, 0); aws_byte_buf_write_u8( &fixture->buffer, 7); aws_byte_buf_write_u8( &fixture->buffer, 0); aws_byte_buf_write_u8( &fixture->buffer, TOPIC_NAME_LEN); aws_byte_buf_write( &fixture->buffer, s_topic_name, TOPIC_NAME_LEN); /* clang-format on */ return AWS_OP_SUCCESS; } static int s_test_unsubscribe_clean_up(struct packet_test_fixture *fixture) { aws_mqtt_packet_unsubscribe_clean_up(fixture->in_packet); aws_mqtt_packet_unsubscribe_clean_up(fixture->out_packet); return AWS_OP_SUCCESS; } static bool s_test_unsubscribe_eq(void *a, void *b, size_t size) { (void)size; struct aws_mqtt_packet_unsubscribe *l = a; struct aws_mqtt_packet_unsubscribe *r = b; if (!s_fixed_header_eq(&l->fixed_header, &r->fixed_header) || l->packet_identifier != r->packet_identifier) { return false; } const size_t length = aws_array_list_length(&l->topic_filters); if (length != aws_array_list_length(&r->topic_filters)) { return false; } for (size_t i = 0; i < length; ++i) { struct aws_byte_cursor *lt = NULL; aws_array_list_get_at_ptr(&l->topic_filters, (void **)<, i); struct aws_byte_cursor *rt = NULL; aws_array_list_get_at_ptr(&r->topic_filters, (void **)&rt, i); AWS_ASSUME(lt && rt); if (!aws_byte_cursor_eq(lt, rt)) { return false; } } return true; } PACKET_TEST(UNSUBSCRIBE, unsubscribe, &s_test_unsubscribe_init, &s_test_unsubscribe_clean_up, &s_test_unsubscribe_eq) /*****************************************************************************/ /* Connection */ static int s_test_connection_init(struct packet_test_fixture *fixture) { /* Init packet */ switch (fixture->type) { case AWS_MQTT_PACKET_PINGREQ: ASSERT_SUCCESS(aws_mqtt_packet_pingreq_init(fixture->in_packet)); break; case AWS_MQTT_PACKET_PINGRESP: ASSERT_SUCCESS(aws_mqtt_packet_pingresp_init(fixture->in_packet)); break; case AWS_MQTT_PACKET_DISCONNECT: ASSERT_SUCCESS(aws_mqtt_packet_disconnect_init(fixture->in_packet)); break; default: AWS_FATAL_ASSERT(false); break; } /* Init buffer */ /* clang-format off */ uint8_t header[] = { (uint8_t)(fixture->type << 4), /* Packet type */ 0, /* Remaining length */ }; /* clang-format on */ aws_byte_buf_write(&fixture->buffer, header, sizeof(header)); return AWS_OP_SUCCESS; } #define PACKET_TEST_CONNETION(e_type, name) \ PACKET_TEST_NAME(e_type, name, connection, &s_test_connection_init, NULL, NULL) PACKET_TEST_CONNETION(PINGREQ, pingreq) PACKET_TEST_CONNETION(PINGRESP, pingresp) PACKET_TEST_CONNETION(DISCONNECT, disconnect) #undef PACKET_TEST_CONNETION #ifdef _MSC_VER # pragma warning(pop) #endif