/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2012-2014 Aleksander Morgado <aleksander@aleksander.es>
*/
#include <config.h>
#include <glib-object.h>
#include <string.h>
#include <stdio.h>
#include "qmi-message.h"
#include "qmi-errors.h"
#include "qmi-error-types.h"
#include "qmi-utils.h"
/*****************************************************************************/
static gchar *
__str_hex (gconstpointer mem,
gsize size,
gchar delimiter)
{
const guint8 *data = mem;
gsize i;
gsize j;
gsize new_str_length;
gchar *new_str;
/* Get new string length. If input string has N bytes, we need:
* - 1 byte for last NUL char
* - 2N bytes for hexadecimal char representation of each byte...
* - N-1 bytes for the separator ':'
* So... a total of (1+2N+N-1) = 3N bytes are needed... */
new_str_length = 3 * size;
/* Allocate memory for new array and initialize contents to NUL */
new_str = g_malloc0 (new_str_length);
/* Print hexadecimal representation of each byte... */
for (i = 0, j = 0; i < size; i++, j += 3) {
/* Print character in output string... */
snprintf (&new_str[j], 3, "%02X", data[i]);
/* And if needed, add separator */
if (i != (size - 1) )
new_str[j + 2] = delimiter;
}
/* Set output string */
return new_str;
}
static void
_g_assert_cmpmem (gconstpointer mem1,
gsize size1,
gconstpointer mem2,
gsize size2)
{
gchar *str1;
gchar *str2;
str1 = __str_hex (mem1, size1, ':');
str2 = __str_hex (mem2, size2, ':');
g_assert_cmpstr (str1, ==, str2);
g_free (str1);
g_free (str2);
}
/*****************************************************************************/
static void
test_message_parse_common (const guint8 *buffer,
guint buffer_len,
guint n_expected_messages)
{
GError *error = NULL;
GByteArray *array;
guint n_messages = 0;
array = g_byte_array_sized_new (buffer_len);
g_byte_array_append (array, buffer, buffer_len);
do {
QmiMessage *message;
gchar *printable;
message = qmi_message_new_from_raw (array, &error);
if (!message) {
if (error) {
if (n_messages < n_expected_messages)
g_printerr ("error creating message from raw data: '%s'\n", error->message);
g_error_free (error);
}
break;
}
printable = qmi_message_get_printable_full (message, NULL, "");
#ifdef TEST_PRINT_MESSAGE
g_print ("\n%s\n", printable);
#endif
g_free (printable);
n_messages++;
qmi_message_unref (message);
} while (array->len > 0);
g_assert_cmpuint (n_messages, ==, n_expected_messages);
g_byte_array_unref (array);
}
static void
test_message_parse_short (void)
{
const guint8 buffer[] = {
0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00, 0x20, 0x00, 0x1a,
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x9b,
0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x66, 0x05
};
test_message_parse_common (buffer, sizeof (buffer), 0);
}
static void
test_message_parse_complete (void)
{
const guint8 buffer[] = {
0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00, 0x20, 0x00, 0x1a,
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x9b,
0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x65, 0x05, 0x12, 0x04, 0x00, 0x01,
0x00, 0x11, 0x05
};
test_message_parse_common (buffer, sizeof (buffer), 1);
}
static void
test_message_parse_complete_and_short (void)
{
const guint8 buffer[] = {
0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00, 0x20, 0x00, 0x1a,
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x9b,
0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x65, 0x05, 0x12, 0x04, 0x00, 0x01,
0x00, 0x11, 0x05, 0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00,
0x20, 0x00, 0x1a, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x02, 0x00, 0x9b, 0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x66, 0x05
};
test_message_parse_common (buffer, sizeof (buffer), 1);
}
static void
test_message_parse_complete_and_complete (void)
{
const guint8 buffer[] = {
0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00, 0x20, 0x00, 0x1a,
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x9b,
0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x65, 0x05, 0x12, 0x04, 0x00, 0x01,
0x00, 0x11, 0x05, 0x01, 0x26, 0x00, 0x80, 0x03, 0x01, 0x02, 0x01, 0x00,
0x20, 0x00, 0x1a, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x02, 0x00, 0x9b, 0x05, 0x11, 0x04, 0x00, 0x01, 0x00, 0x65, 0x05, 0x12,
0x04, 0x00, 0x01, 0x00, 0x11, 0x05
};
test_message_parse_common (buffer, sizeof (buffer), 2);
}
static void
test_message_overflow_common (const guint8 *buffer,
guint buffer_len)
{
QmiMessage *message;
GByteArray *array;
GError *error = NULL;
gchar *printable;
array = g_byte_array_sized_new (buffer_len);
g_byte_array_append (array, buffer, buffer_len);
message = qmi_message_new_from_raw (array, &error);
g_assert_no_error (error);
g_assert (message);
printable = qmi_message_get_printable_full (message, NULL, "");
g_print ("\n%s\n", printable);
g_assert (strstr (printable, "ERROR: Reading TLV would overflow"));
g_free (printable);
g_byte_array_unref (array);
qmi_message_unref (message);
}
static void
test_message_parse_wrong_tlv (void)
{
const guint8 buffer[] = {
0x01, 0x4F, 0x00, 0x80, 0x03, 0x03, 0x02, 0x01, 0x00, 0x24, 0x00, 0x43,
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x04, 0x00, 0x02,
0x03, 0x00, 0x00, 0x1D, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x02,
0x00, 0x00, 0x00, 0x15, 0x03, 0x00, 0x01, 0x05, 0x01, 0x12, 0x0E, 0x00,
0x36, 0x01, 0x04, 0x01, 0x09, 0x20, 0x54, 0x2D, 0x4D, 0x6F, 0x62, 0x69,
0x6C, 0x65, 0x11, 0x02, 0x00, 0x01, 0x05, 0x10, 0x01, 0x00, 0x01, 0x01,
0x06, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x05
};
test_message_overflow_common (buffer, G_N_ELEMENTS (buffer));
}
static void
test_message_parse_missing_size (void)
{
/* PDS Event Report indication: NMEA position */
const guint8 buffer[] = {
0x01, /* marker */
0x10, 0x00, /* qmux length */
0x80, /* qmux flags */
0x06, /* service: PDS */
0x03, /* client */
0x04, /* service flags: Indication */
0x01, 0x00, /* transaction */
0x01, 0x00, /* message: Event Report */
0x04, 0x00, /* all tlvs length: 4 bytes */
/* TLV */
0x11, /* type: Extended NMEA Position (1 guint8 and one 16-bit-sized string) */
0x01, 0x00, /* length: 1 byte (WE ONLY GIVE THE GUINT8!!!) */
0x01
};
test_message_overflow_common (buffer, G_N_ELEMENTS (buffer));
}
/*****************************************************************************/
static void
test_message_new_request (void)
{
static const guint8 expected_buffer [] = {
0x01, /* marker */
0x0C, 0x00, /* qmux length */
0x00, /* qmux flags */
0x02, /* service: DMS */
0x01, /* client id */
0x00, /* service flags */
0x02, 0x00, /* transaction */
0xFF, 0xFF, /* message id */
0x00, 0x00, /* all tlvs length */
};
QmiMessage *self;
GError *error = NULL;
const guint8 *buffer;
gsize buffer_length = 0;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
g_assert (self);
buffer = qmi_message_get_raw (self, &buffer_length, &error);
g_assert_no_error (error);
g_assert (buffer != NULL);
g_assert_cmpuint (buffer_length, >, 0);
_g_assert_cmpmem (buffer, buffer_length, expected_buffer, sizeof (expected_buffer));
qmi_message_unref (self);
}
static void
test_message_new_request_from_data (void)
{
static const guint8 expected_buffer [] = {
0x00, /* service flags */
0x02, 0x00, /* transaction */
0xFF, 0xFF, /* message id */
0x00, 0x00, /* all tlvs length */
};
GByteArray *qmi;
QmiMessage *self;
GError *error = NULL;
const guint8 *buffer;
gsize buffer_length = 0;
/* set up service header */
qmi = g_byte_array_new ();
g_byte_array_append (qmi, expected_buffer, sizeof (expected_buffer));
self = qmi_message_new_from_data (QMI_SERVICE_DMS, 0x01, qmi, NULL);
g_assert (self);
/* check that the QMUX header contains the right values*/
g_assert_cmpuint (qmi_message_get_service (self), ==, QMI_SERVICE_DMS);
g_assert_cmpuint (qmi_message_get_client_id (self), ==, 0x01);
/* length (13) = qmux marker (1) + qmux header length (5) + qmi header length (7) */
g_assert_cmpuint (qmi_message_get_length (self), ==, 13);
/* check that transaction and message IDs line up */
g_assert_cmpuint (qmi_message_get_transaction_id (self), ==, 0x02);
g_assert_cmpuint (qmi_message_get_message_id (self), ==, 0xFFFF);
buffer = qmi_message_get_raw (self, &buffer_length, &error);
g_assert_no_error (error);
g_assert (buffer != NULL);
g_assert_cmpuint (buffer_length, >, 0);
/* check that we have a qmux marker so we don't break framing */
g_assert_cmpuint (buffer[0], ==, 0x01);
/* make sure the qmi portion of the message is what we expect */
buffer = qmi_message_get_data (self, &buffer_length, &error);
g_assert_no_error (error);
g_assert (buffer != NULL);
g_assert_cmpuint (buffer_length, >, 0);
_g_assert_cmpmem (buffer, buffer_length, expected_buffer, sizeof (expected_buffer));
qmi_message_unref (self);
}
static void
test_message_new_response_ok (void)
{
static const guint8 expected_buffer [] = {
0x01, /* marker */
0x13, 0x00, /* qmux length */
0x80, /* qmux flags */
0x02, /* service: DMS */
0x01, /* client id */
0x02, /* service flags */
0x02, 0x00, /* transaction */
0xFF, 0xFF, /* message id */
0x07, 0x00, /* all tlvs length */
/* TLV */
0x02, /* tlv type */
0x04, 0x00, /* tlv size */
0x00, 0x00, 0x00, 0x00
};
QmiMessage *request;
QmiMessage *response;
GError *error = NULL;
const guint8 *buffer;
gsize buffer_length = 0;
request = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
g_assert (request);
response = qmi_message_response_new (request, QMI_PROTOCOL_ERROR_NONE);
g_assert (response);
buffer = qmi_message_get_raw (response, &buffer_length, &error);
g_assert_no_error (error);
g_assert (buffer != NULL);
g_assert_cmpuint (buffer_length, >, 0);
_g_assert_cmpmem (buffer, buffer_length, expected_buffer, sizeof (expected_buffer));
qmi_message_unref (request);
qmi_message_unref (response);
}
static void
test_message_new_response_error (void)
{
static const guint8 expected_buffer [] = {
0x01, /* marker */
0x13, 0x00, /* qmux length */
0x80, /* qmux flags */
0x02, /* service: DMS */
0x01, /* client id */
0x02, /* service flags */
0x02, 0x00, /* transaction */
0xFF, 0xFF, /* message id */
0x07, 0x00, /* all tlvs length */
/* TLV */
0x02, /* tlv type */
0x04, 0x00, /* tlv size */
0x01, 0x00, 0x03, 0x00
};
QmiMessage *request;
QmiMessage *response;
GError *error = NULL;
const guint8 *buffer;
gsize buffer_length = 0;
request = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
g_assert (request);
response = qmi_message_response_new (request, QMI_PROTOCOL_ERROR_INTERNAL);
g_assert (response);
buffer = qmi_message_get_raw (response, &buffer_length, &error);
g_assert_no_error (error);
g_assert (buffer != NULL);
g_assert_cmpuint (buffer_length, >, 0);
_g_assert_cmpmem (buffer, buffer_length, expected_buffer, sizeof (expected_buffer));
qmi_message_unref (request);
qmi_message_unref (response);
}
/*****************************************************************************/
static void
test_message_tlv_write_empty (void)
{
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
qmi_message_unref (self);
}
static void
test_message_tlv_write_reset (void)
{
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
gsize previous_size;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
previous_size = qmi_message_get_length (self);
/* Test reset just after init */
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
qmi_message_tlv_write_reset (self, init_offset);
g_assert_cmpuint (previous_size, ==, qmi_message_get_length (self));
/* Test reset after adding variables */
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_guint8 (self, 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
qmi_message_tlv_write_reset (self, init_offset);
g_assert_cmpuint (previous_size, ==, qmi_message_get_length (self));
qmi_message_unref (self);
}
static void
test_message_tlv_rw_8 (void)
{
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
gsize expected_tlv_payload_size = 0;
guint16 tlv_length = 0;
gsize offset;
guint8 uint8;
gint8 int8;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* Add one of each */
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_gint8 (self, 0 - 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &uint8, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint8, ==, 0x12);
ret = qmi_message_tlv_read_gint8 (self, init_offset, &offset, &int8, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int8, ==, 0 - 0x12);
qmi_message_unref (self);
}
static void
test_message_tlv_rw_16 (void)
{
guint n_bytes_prefixed;
/* We'll add [0 or 1] bytes before the actual 16-bit values, so that we
* check all possible memory alignments. */
for (n_bytes_prefixed = 0; n_bytes_prefixed <= 1; n_bytes_prefixed++) {
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
guint16 uint16;
gint16 int16;
guint i;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
for (i = 0; i < n_bytes_prefixed; i++) {
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0xFF, &error);
g_assert_no_error (error);
g_assert (ret);
}
/* Add one of each */
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_guint16 (self, QMI_ENDIAN_LITTLE, 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_gint16 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_guint16 (self, QMI_ENDIAN_BIG, 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_gint16 (self, QMI_ENDIAN_BIG, 0 - 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
for (i = 0; i < n_bytes_prefixed; i++) {
guint8 aux;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &aux, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (aux, ==, 0xFF);
}
ret = qmi_message_tlv_read_guint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint16, ==, 0x1212);
ret = qmi_message_tlv_read_gint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int16, ==, 0 - 0x1212);
ret = qmi_message_tlv_read_guint16 (self, init_offset, &offset, QMI_ENDIAN_BIG, &uint16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint16, ==, 0x1212);
ret = qmi_message_tlv_read_gint16 (self, init_offset, &offset, QMI_ENDIAN_BIG, &int16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int16, ==, 0 - 0x1212);
qmi_message_unref (self);
}
}
static void
test_message_tlv_rw_32 (void)
{
guint n_bytes_prefixed;
/* We'll add [0, 1, 2, 3] bytes before the actual 32-bit values, so that we
* check all possible memory alignments. */
for (n_bytes_prefixed = 0; n_bytes_prefixed <= 3; n_bytes_prefixed++) {
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
guint32 uint32;
gint32 int32;
guint i;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
for (i = 0; i < n_bytes_prefixed; i++) {
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0xFF, &error);
g_assert_no_error (error);
g_assert (ret);
}
/* Add one of each */
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_guint32 (self, QMI_ENDIAN_LITTLE, 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_gint32 (self, QMI_ENDIAN_LITTLE, 0 - 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_guint32 (self, QMI_ENDIAN_BIG, 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_gint32 (self, QMI_ENDIAN_BIG, 0 - 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
for (i = 0; i < n_bytes_prefixed; i++) {
guint8 aux;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &aux, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (aux, ==, 0xFF);
}
ret = qmi_message_tlv_read_guint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint32, ==, 0x12121212);
ret = qmi_message_tlv_read_gint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int32, ==, 0 - 0x12121212);
ret = qmi_message_tlv_read_guint32 (self, init_offset, &offset, QMI_ENDIAN_BIG, &uint32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint32, ==, 0x12121212);
ret = qmi_message_tlv_read_gint32 (self, init_offset, &offset, QMI_ENDIAN_BIG, &int32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int32, ==, 0 - 0x12121212);
qmi_message_unref (self);
}
}
static void
test_message_tlv_rw_64 (void)
{
guint n_bytes_prefixed;
/* We'll add [0, 1, 2, 3, 4, 5, 6, 7] bytes before the actual 64-bit values,
* so that we check all possible memory alignments. */
for (n_bytes_prefixed = 0; n_bytes_prefixed <= 7; n_bytes_prefixed++) {
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
guint64 uint64;
gint64 int64;
guint i;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
for (i = 0; i < n_bytes_prefixed; i++) {
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0xFF, &error);
g_assert_no_error (error);
g_assert (ret);
}
/* Add one of each */
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_guint64 (self, QMI_ENDIAN_LITTLE, 0x1212121212121212ULL, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_gint64 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212121212121212LL, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_guint64 (self, QMI_ENDIAN_BIG, 0x1212121212121212ULL, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_gint64 (self, QMI_ENDIAN_BIG, 0 - 0x1212121212121212LL, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
for (i = 0; i < n_bytes_prefixed; i++) {
guint8 aux;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &aux, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (aux, ==, 0xFF);
}
ret = qmi_message_tlv_read_guint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint64, ==, 0x1212121212121212ULL);
ret = qmi_message_tlv_read_gint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int64, ==, 0 - 0x1212121212121212LL);
ret = qmi_message_tlv_read_guint64 (self, init_offset, &offset, QMI_ENDIAN_BIG, &uint64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint64, ==, 0x1212121212121212ULL);
ret = qmi_message_tlv_read_gint64 (self, init_offset, &offset, QMI_ENDIAN_BIG, &int64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int64, ==, 0 - 0x1212121212121212LL);
qmi_message_unref (self);
}
}
static void
test_message_tlv_rw_sized (void)
{
guint sized[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
guint sized_i;
for (sized_i = 0; sized_i < G_N_ELEMENTS (sized); sized_i++) {
guint n_bytes_prefixed;
/* We'll add [0, 1, 2, 3, 4, 5, 6, 7] bytes before the actual N-bit values,
* so that we check all possible memory alignments. */
for (n_bytes_prefixed = 0; n_bytes_prefixed <= sized[sized_i] - 1; n_bytes_prefixed++) {
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
guint64 uint64;
guint i;
guint64 value;
guint64 tmp;
value = 0x1212121212121212ULL;
tmp = 0xFF;
for (i = 1; i < sized[sized_i]; i++) {
tmp <<= 8;
tmp |= 0xFF;
}
value &= tmp;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
for (i = 0; i < n_bytes_prefixed; i++) {
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0xFF, &error);
g_assert_no_error (error);
g_assert (ret);
}
/* Add one of each */
expected_tlv_payload_size += sized[sized_i];
ret = qmi_message_tlv_write_sized_guint (self, sized[sized_i], QMI_ENDIAN_LITTLE, value, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += sized[sized_i];
ret = qmi_message_tlv_write_sized_guint (self, sized[sized_i], QMI_ENDIAN_BIG, value, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
for (i = 0; i < n_bytes_prefixed; i++) {
guint8 aux;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &aux, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (aux, ==, 0xFF);
}
qmi_message_tlv_read_sized_guint (self, init_offset, &offset, sized[sized_i], QMI_ENDIAN_LITTLE, &uint64, &error);
g_assert_cmpuint (uint64, ==, value);
qmi_message_tlv_read_sized_guint (self, init_offset, &offset, sized[sized_i], QMI_ENDIAN_BIG, &uint64, &error);
g_assert_cmpuint (uint64, ==, value);
qmi_message_unref (self);
}
}
}
static void
test_message_tlv_rw_strings (void)
{
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
gchar *str;
gchar fixed_str[5];
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* FIXED SIZE */
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_string (self, 0, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* 1-BYTE PREFIX */
expected_tlv_payload_size += 5;
ret = qmi_message_tlv_write_string (self, 1, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* 2-BYTE PREFIX */
expected_tlv_payload_size += 6;
ret = qmi_message_tlv_write_string (self, 2, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* FIXED SIZE */
expected_tlv_payload_size += 0;
ret = qmi_message_tlv_write_string (self, 0, "", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* 1-BYTE PREFIX */
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_string (self, 1, "", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* 2-BYTE PREFIX */
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_string (self, 2, "", -1, &error);
g_assert_no_error (error);
g_assert (ret);
/* 0-BYTE PREFIX (same as fixed size, but LAST in TLV) */
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_string (self, 0, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
ret = qmi_message_tlv_read_fixed_size_string (self, init_offset, &offset, 4, fixed_str, &error);
g_assert_no_error (error);
g_assert (ret);
fixed_str[4] = '\0';
g_assert_cmpstr (fixed_str, ==, "abcd");
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "abcd");
g_free (str);
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 2, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "abcd");
g_free (str);
fixed_str[0] = 'z';
ret = qmi_message_tlv_read_fixed_size_string (self, init_offset, &offset, 0, fixed_str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (fixed_str[0], ==, 'z');
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "");
g_free (str);
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 2, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "");
g_free (str);
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 0, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "abcd");
g_free (str);
/* There's no other string added, but we can try to read a new one without
* size prefix, and we should get a 0-length string */
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 0, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "");
g_free (str);
qmi_message_unref (self);
}
static void
test_message_tlv_rw_mixed (void)
{
QmiMessage *self;
GError *error = NULL;
gboolean ret;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gsize expected_tlv_payload_size = 0;
guint8 uint8;
gint8 int8;
guint16 uint16;
gint16 int16;
guint32 uint32;
gint32 int32;
guint64 uint64;
gint64 int64;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* Add one of each */
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_guint8 (self, 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 1;
ret = qmi_message_tlv_write_gint8 (self, 0 - 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_guint16 (self, QMI_ENDIAN_LITTLE, 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 2;
ret = qmi_message_tlv_write_gint16 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_guint32 (self, QMI_ENDIAN_LITTLE, 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_gint32 (self, QMI_ENDIAN_LITTLE, 0 - 0x12121212, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_guint64 (self, QMI_ENDIAN_LITTLE, 0x1212121212121212ULL, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 8;
ret = qmi_message_tlv_write_gint64 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212121212121212LL, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 4;
ret = qmi_message_tlv_write_string (self, 0, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 5;
ret = qmi_message_tlv_write_string (self, 1, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
expected_tlv_payload_size += 6;
ret = qmi_message_tlv_write_string (self, 2, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
g_assert_cmpuint (tlv_length, ==, expected_tlv_payload_size);
offset = 0;
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &uint8, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint8, ==, 0x12);
ret = qmi_message_tlv_read_gint8 (self, init_offset, &offset, &int8, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int8, ==, 0 - 0x12);
ret = qmi_message_tlv_read_guint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint16, ==, 0x1212);
ret = qmi_message_tlv_read_gint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int16, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int16, ==, 0 - 0x1212);
ret = qmi_message_tlv_read_guint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint32, ==, 0x12121212);
ret = qmi_message_tlv_read_gint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int32, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int32, ==, 0 - 0x12121212);
ret = qmi_message_tlv_read_guint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (uint64, ==, 0x1212121212121212ULL);
ret = qmi_message_tlv_read_gint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int64, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpuint (int64, ==, 0 - 0x1212121212121212LL);
qmi_message_unref (self);
}
static void
test_message_tlv_write_overflow (void)
{
QmiMessage *self;
GError *error = NULL;
gsize init_offset;
gboolean ret;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* Add guint8 values until we get to the maximum message size */
while (qmi_message_get_length (self) < G_MAXUINT16) {
ret = qmi_message_tlv_write_guint8 (self, 0x12, &error);
g_assert_no_error (error);
g_assert (ret);
}
/* Message is max size now, don't allow more variables */
ret = qmi_message_tlv_write_guint8 (self, 0x12, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_gint8 (self, 0 - 0x12, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_guint16 (self, QMI_ENDIAN_LITTLE, 0x1212, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_gint16 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_guint32 (self, QMI_ENDIAN_LITTLE, 0x12121212, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_gint32 (self, QMI_ENDIAN_LITTLE, 0 - 0x12121212, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_guint64 (self, QMI_ENDIAN_LITTLE, 0x1212121212121212ULL, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_gint64 (self, QMI_ENDIAN_LITTLE, 0 - 0x1212121212121212LL, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_sized_guint (self, 1, QMI_ENDIAN_LITTLE, 0x12, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_string (self, 0, "a", -1, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_string (self, 1, "a", -1, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_write_string (self, 2, "a", -1, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
/* Writing an empty string with a 0-size prefix is actually valid :) */
ret = qmi_message_tlv_write_string (self, 0, "", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Message is max size now, don't allow more TLVs */
init_offset = qmi_message_tlv_write_init (self, 0x02, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (init_offset == 0);
g_clear_error (&error);
qmi_message_unref (self);
}
static void
test_message_tlv_read_overflow_message (void)
{
QmiMessage *self;
GError *error = NULL;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gboolean ret;
gchar *str;
guint8 uint8;
gint8 int8;
guint16 uint16;
gint16 int16;
guint32 uint32;
gint32 int32;
guint64 uint64;
gint64 int64;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* Create a 1-byte size prefixed string manually, with a wrong length (out of message) */
ret = qmi_message_tlv_write_guint8 (self, 5, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_string (self, 0, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
offset = 0;
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
qmi_message_unref (self);
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_string (self, 1, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
offset = 0;
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "abcd");
g_free (str);
/* Reading more will fail */
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 2, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &uint8, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint8 (self, init_offset, &offset, &int8, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint16, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int16, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint32, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int32, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint64, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int64, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
qmi_message_unref (self);
}
static void
test_message_tlv_read_overflow_tlv (void)
{
QmiMessage *self;
GError *error = NULL;
gsize init_offset;
guint16 tlv_length = 0;
gsize offset;
gboolean ret;
gchar *str;
guint8 uint8;
gint8 int8;
guint16 uint16;
gint16 int16;
guint32 uint32;
gint32 int32;
guint64 uint64;
gint64 int64;
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
/* Create a 1-byte size prefixed string manually, with a wrong length (out of tlv) */
ret = qmi_message_tlv_write_guint8 (self, 5, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_string (self, 0, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
init_offset = qmi_message_tlv_write_init (self, 0x02, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_string (self, 1, "efgh", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
offset = 0;
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
qmi_message_unref (self);
self = qmi_message_new (QMI_SERVICE_DMS, 0x01, 0x02, 0xFFFF);
init_offset = qmi_message_tlv_write_init (self, 0x01, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_string (self, 1, "abcd", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
init_offset = qmi_message_tlv_write_init (self, 0x02, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
ret = qmi_message_tlv_write_string (self, 1, "efgh", -1, &error);
g_assert_no_error (error);
g_assert (ret);
ret = qmi_message_tlv_write_complete (self, init_offset, &error);
g_assert_no_error (error);
g_assert (ret);
/* Now read */
init_offset = qmi_message_tlv_read_init (self, 0x01, &tlv_length, &error);
g_assert_no_error (error);
g_assert (init_offset > 0);
offset = 0;
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_no_error (error);
g_assert (ret);
g_assert_cmpstr (str, ==, "abcd");
g_free (str);
/* Reading more will fail */
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 1, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_string (self, init_offset, &offset, 2, 0, &str, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint8 (self, init_offset, &offset, &uint8, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint8 (self, init_offset, &offset, &int8, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint16, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint16 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int16, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint32, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint32 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int32, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_guint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &uint64, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
ret = qmi_message_tlv_read_gint64 (self, init_offset, &offset, QMI_ENDIAN_LITTLE, &int64, &error);
g_assert_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_TLV_TOO_LONG);
g_assert (!ret);
g_clear_error (&error);
qmi_message_unref (self);
}
/*****************************************************************************/
static void
test_message_set_transaction_id_ctl (void)
{
GByteArray *buffer;
QmiMessage *message;
GError *error = NULL;
guint8 ctl_message[] = {
0x01, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, /* TRID to update */
0x22, 0x00, 0x04, 0x00, 0x01, 0x01, 0x00, 0x01
};
/* CTL message */
buffer = g_byte_array_append (g_byte_array_sized_new (G_N_ELEMENTS (ctl_message)), ctl_message, G_N_ELEMENTS (ctl_message));
message = qmi_message_new_from_raw (buffer, &error);
g_assert_no_error (error);
g_assert (message);
qmi_message_set_transaction_id (message, 0x55);
g_assert_cmpuint (qmi_message_get_transaction_id (message), ==, 0x55);
qmi_message_unref (message);
g_byte_array_unref (buffer);
}
static void
test_message_set_transaction_id_services (void)
{
GByteArray *buffer;
QmiMessage *message;
GError *error = NULL;
guint8 dms_message[] = {
0x01, 0x0C, 0x00, 0x00, 0x02, 0x01, 0x00,
0xFF, 0xFF, /* TRID to update */
0x25, 0x00, 0x00, 0x00
};
/* DMS message */
buffer = g_byte_array_append (g_byte_array_sized_new (G_N_ELEMENTS (dms_message)), dms_message, G_N_ELEMENTS (dms_message));
message = qmi_message_new_from_raw (buffer, &error);
g_assert_no_error (error);
g_assert (message);
qmi_message_set_transaction_id (message, 0x5566);
g_assert_cmpuint (qmi_message_get_transaction_id (message), ==, 0x5566);
qmi_message_unref (message);
g_byte_array_unref (buffer);
}
/*****************************************************************************/
int main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/libqmi-glib/message/parse/short", test_message_parse_short);
g_test_add_func ("/libqmi-glib/message/parse/complete", test_message_parse_complete);
g_test_add_func ("/libqmi-glib/message/parse/complete-and-short", test_message_parse_complete_and_short);
g_test_add_func ("/libqmi-glib/message/parse/complete-and-complete", test_message_parse_complete_and_complete);
g_test_add_func ("/libqmi-glib/message/parse/wrong-tlv", test_message_parse_wrong_tlv);
g_test_add_func ("/libqmi-glib/message/parse/missing-size", test_message_parse_missing_size);
g_test_add_func ("/libqmi-glib/message/new/request", test_message_new_request);
g_test_add_func ("/libqmi-glib/message/new/request-from-data", test_message_new_request_from_data);
g_test_add_func ("/libqmi-glib/message/new/response/ok", test_message_new_response_ok);
g_test_add_func ("/libqmi-glib/message/new/response/error", test_message_new_response_error);
g_test_add_func ("/libqmi-glib/message/tlv-write/empty", test_message_tlv_write_empty);
g_test_add_func ("/libqmi-glib/message/tlv-write/reset", test_message_tlv_write_reset);
g_test_add_func ("/libqmi-glib/message/tlv-rw/8", test_message_tlv_rw_8);
g_test_add_func ("/libqmi-glib/message/tlv-rw/16", test_message_tlv_rw_16);
g_test_add_func ("/libqmi-glib/message/tlv-rw/32", test_message_tlv_rw_32);
g_test_add_func ("/libqmi-glib/message/tlv-rw/64", test_message_tlv_rw_64);
g_test_add_func ("/libqmi-glib/message/tlv-rw/sized", test_message_tlv_rw_sized);
g_test_add_func ("/libqmi-glib/message/tlv-rw/strings", test_message_tlv_rw_strings);
g_test_add_func ("/libqmi-glib/message/tlv-rw/mixed", test_message_tlv_rw_mixed);
g_test_add_func ("/libqmi-glib/message/tlv-write/overflow", test_message_tlv_write_overflow);
g_test_add_func ("/libqmi-glib/message/tlv-read/overflow-message", test_message_tlv_read_overflow_message);
g_test_add_func ("/libqmi-glib/message/tlv-read/overflow-tlv", test_message_tlv_read_overflow_tlv);
g_test_add_func ("/libqmi-glib/message/set-transaction-id/ctl", test_message_set_transaction_id_ctl);
g_test_add_func ("/libqmi-glib/message/set-transaction-id/services", test_message_set_transaction_id_services);
return g_test_run ();
}