diff --git a/tests/encode_packet.c b/tests/encode_packet.c index c8826a9..ca6e018 100644 --- a/tests/encode_packet.c +++ b/tests/encode_packet.c @@ -26,133 +26,103 @@ TestResult test_vl_int_16384(void) { TestResult test_vl_int_data_0(void) { char data[] = { 0 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(0, buffer); - TESTASSERT( - ( - (buffer->position == 1) - && - (memcmp(buffer->data, data, 1) == 0) - ), - "Variable length int of 0 should result in [0x00]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_vl_int_data_127(void) { char data[] = { 127 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(127, buffer); - TESTASSERT( - ( - (buffer->position == 1) - && - (memcmp(buffer->data, data, 1) == 0) - ), - "Variable length int of 127 should result in [0x7f]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_vl_int_data_128(void) { char data[] = { 0x80, 0x01 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(128, buffer); - TESTASSERT( - ( - (buffer->position == 2) - && - (memcmp(buffer->data, data, 2) == 0) - ), - "Variable length int of 128 should result in [0x80, 0x01]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_vl_int_data_16383(void) { char data[] = { 0xff, 0x7f }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(16383, buffer); - TESTASSERT( - ( - (buffer->position == 2) - && - (memcmp(buffer->data, data, 2) == 0) - ), - "Variable length int of 16383 should result in [0xff, 0x7f]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_vl_int_data_16384(void) { char data[] = { 0x80, 0x80, 0x01 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(16384, buffer); - TESTASSERT( - ( - (buffer->position == 3) - && - (memcmp(buffer->data, data, 3) == 0) - ), - "Variable length int of 16384 should result in [0x80, 0x80, 0x01]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_vl_int_data_32767(void) { char data[] = { 0xff, 0xff, 0x01 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); variable_length_int_encode(32767, buffer); - TESTASSERT( - ( - (buffer->position == 3) - && - (memcmp(buffer->data, data, 3) == 0) - ), - "Variable length int of 32767 should result in [0xff, 0xff, 0x01]"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } // UTF-8 String encoding TestResult test_utf8_string_null(void) { char data[] = { 0x00, 0x00 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); size_t sz = utf8_string_encode(NULL, buffer); - TESTASSERT( - ( - (buffer->position == 2) - && - (sz == 2) - && - (memcmp(buffer->data, data, 2) == 0) - ), - "NULL String should result in [0x00, 0x00]"); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_utf8_string_empty(void) { char data[] = { 0x00, 0x00 }; - Buffer *buffer = buffer_allocate(5); + Buffer *buffer = buffer_allocate(sizeof(data)); size_t sz = utf8_string_encode("", buffer); - TESTASSERT( - ( - (buffer->position == 2) - && - (sz == 2) - && - (memcmp(buffer->data, data, 2) == 0) - ), - "Empty String should result in [0x00, 0x00]"); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } TestResult test_utf8_string_hello(void) { char data[] = { 0x00, 0x05, 'h', 'e', 'l', 'l', 'o' }; - Buffer *buffer = buffer_allocate(10); + Buffer *buffer = buffer_allocate(sizeof(data)); size_t sz = utf8_string_encode("hello", buffer); - TESTASSERT( - ( - (buffer->position == 7) - && - (sz == 7) - && - (memcmp(buffer->data, data, 7) == 0) - ), - "\"hello\" String should result in [0x00, 0x05, 'h', 'e', 'l', 'l', 'o']"); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } // make header @@ -160,17 +130,100 @@ TestResult test_make_header(void) { char data[] = { 0x10, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; Buffer *buffer = make_buffer_for_header(5, PacketTypeConnect); - TESTASSERT( - ( - (buffer->len == 7) - && - (memcmp(buffer->data, data, 7) == 0) - && - (buffer->position == 2) - ), - "Header should be valid"); + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + buffer + ); } +TestResult test_encode_connect_simple(void) { + char data[] = { + 0x10, 0x10, // header + 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x04, 0x02, 0x00, 0x0a, // var header + 0x00, 0x04, 't', 'e', 's', 't' // client id + }; + ConnectPayload *payload = calloc(1, sizeof(ConnectPayload)); + + payload->client_id = "test"; + payload->protocol_level = 4; + payload->keepalive_interval = 10; + payload->clean_session = 1; + + Buffer *encoded = encode_connect(payload); + free(payload); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + encoded + ); +} + +TestResult test_encode_connect_will(void) { + char data[] = { + 0x10, 0x2d, // header + 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x04, 0x2e, 0x00, 0x0a, // var header + 0x00, 0x04, 't', 'e', 's', 't', // client id + 0x00, 0x0d, 't', 'e', 's', 't', '/', 'l', 'a', 's', 't', 'w', 'i', 'l', 'l', + 0x00, 0x0c, 'd', 'i', 's', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'e', 'd', + + }; + ConnectPayload *payload = calloc(1, sizeof(ConnectPayload)); + + payload->client_id = "test"; + payload->protocol_level = 4; + payload->keepalive_interval = 10; + payload->clean_session = 1; + + payload->will_topic = "test/lastwill"; + payload->will_message = "disconnected"; + payload->will_qos = MQTT_QOS_1; + payload->retain_will = true; + + Buffer *encoded = encode_connect(payload); + free(payload); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + encoded + ); +} + +TestResult test_encode_connect_auth(void) { + char data[] = { + 0x10, 0x39, // header + 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x04, 0xee, 0x00, 0x0a, // var header + 0x00, 0x04, 't', 'e', 's', 't', // client id + 0x00, 0x0d, 't', 'e', 's', 't', '/', 'l', 'a', 's', 't', 'w', 'i', 'l', 'l', + 0x00, 0x0c, 'd', 'i', 's', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'e', 'd', + 0x00, 0x04, 'a', 'n', 'o', 'n', // username + 0x00, 0x04, 't', 'e', 's', 't' // password + }; + ConnectPayload *payload = calloc(1, sizeof(ConnectPayload)); + + payload->client_id = "test"; + payload->protocol_level = 4; + payload->keepalive_interval = 10; + payload->clean_session = 1; + + payload->will_topic = "test/lastwill"; + payload->will_message = "disconnected"; + payload->will_qos = MQTT_QOS_1; + payload->retain_will = true; + + payload->username = "anon"; + payload->password = "test"; + + Buffer *encoded = encode_connect(payload); + free(payload); + + return TESTMEMCMP( + buffer_from_data_copy(data, sizeof(data)), + encoded + ); +} + +// not implemented placeholder + TestResult not_implemented(void) { TESTRESULT(TestStatusSkipped, "Not implemented"); } @@ -192,7 +245,9 @@ TESTS( TEST("UTF-8 string encode empty string", test_utf8_string_empty), TEST("UTF-8 string encode \"hello\"", test_utf8_string_hello), TEST("Make header", test_make_header), - TEST("Encode Connect", not_implemented), + TEST("Encode Connect simple", test_encode_connect_simple), + TEST("Encode Connect with will", test_encode_connect_will), + TEST("Encode Connect with auth", test_encode_connect_auth), TEST("Encode ConnAck", not_implemented), TEST("Encode Publish", not_implemented), TEST("Encode PubAck", not_implemented), diff --git a/tests/test.h b/tests/test.h index 13d8508..ce07ae1 100644 --- a/tests/test.h +++ b/tests/test.h @@ -7,16 +7,20 @@ #include #include "cputime.h" +#include "buffer.h" typedef enum { TestStatusSkipped = 0, TestStatusFailure, TestStatusOk, + TestStatusFailureHexdump } TestStatus; typedef struct { TestStatus status; char *message; + Buffer *buffer; + Buffer *template; } TestResult; typedef TestResult (*TestPointer)(void); @@ -38,7 +42,8 @@ extern DefinedTest defined_tests[]; TEST(NULL, NULL) \ } -#define TESTRESULT(_status, _message) return (TestResult){ _status, _message } +#define TESTRESULT(_status, _message) return (TestResult){ _status, _message, NULL, NULL } +#define TESTRESULT_BUFFER(_status, _message, _buffer, _template) return (TestResult){ _status, _message, _buffer, _template } #ifdef TIMETRIAL # define TESTASSERT(_assertion, _message) return (TestResult){ (_assertion) ? TestStatusOk : TestStatusFailure, NULL } @@ -46,9 +51,22 @@ extern DefinedTest defined_tests[]; # define TESTASSERT(_assertion, _message) return (TestResult){ (_assertion) ? TestStatusOk : TestStatusFailure, _message } #endif +static inline TestResult TESTMEMCMP(Buffer *template, Buffer *check) { + if (template->len != check->len) { + TESTRESULT_BUFFER(TestStatusFailureHexdump, "Buffer size differs from template", check, template); + } + if (memcmp(template->data, check->data, template->len) == 0) { + TESTRESULT(TestStatusOk, "Buffer matches template"); + } else { + TESTRESULT_BUFFER(TestStatusFailureHexdump, "Buffer and template differ", check, template); + } +} + void timetrial(DefinedTest *test); int main(int argc, char **argv) { + bool failure_seen = false; + for(DefinedTest *test = defined_tests; test->run != NULL; test++) { TestResult result = test->run(); switch (result.status) { @@ -67,16 +85,31 @@ int main(int argc, char **argv) { } break; case TestStatusFailure: + failure_seen = true; fprintf(stderr, "%s:%d: error: Test %s failed\n", test->file, test->line, test->name); if (result.message) { fprintf(stderr, " -> %s\n", result.message); } - return 1; + break; + case TestStatusFailureHexdump: + failure_seen = true; + fprintf(stderr, "%s:%d: error: Test %s failed\n", test->file, test->line, test->name); + if (result.message) { + fprintf(stderr, " -> %s\n", result.message); + } + if (result.template) { + fprintf(stderr, " -> Template (%d bytes)\n", result.template->len); + buffer_hexdump(result.template, 5); + } + if (result.buffer) { + fprintf(stderr, " -> Buffer (%d bytes)\n", result.buffer->len); + buffer_hexdump(result.buffer, 5); + } break; } } - return 0; + return failure_seen; } #ifdef TIMETRIAL