#if defined(HAVE_CONFIG_H) #include "config_ac.h" #endif #include #include #include "libipm.h" #include "os_calls.h" #include "string_calls.h" #include "trans.h" #include "test_libipm.h" /* Random(ish) values for test_libipm_append_all_test */ #define ALL_TEST_y_VALUE 45 #define ALL_TEST_b_VALUE 0 #define ALL_TEST_n_VALUE -14 #define ALL_TEST_q_VALUE 327 #define ALL_TEST_i_VALUE -100000 #define ALL_TEST_u_VALUE 100000 #define ALL_TEST_x_VALUE -4000000000L #define ALL_TEST_t_VALUE 8000000000L #define ALL_TEST_s_VALUE \ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' #define ALL_TEST_B_VALUE 'a', 'z', 'A', 'Z', '0', '9', '#' /* This macro generates two unsigned char values, separated by a comma, * representing a 2's complement little-endian 16-bit integer */ #define BITS16_LE(x) ((x) & 0xff), (((unsigned int)(x) >> 8) & 0xff) /* This macro generates four unsigned char values, separated by a comma, * representing a 2's complement little-endian 32-bit integer */ #define BITS32_LE(x) BITS16_LE((x) & 0xffff), \ BITS16_LE(((unsigned int)(x) >> 16) & 0xffff) /* This macro generates eight unsigned char values, separated by a comma, * representing a 2's complement little-endian 64-bit integer */ #define BITS64_LE(x) BITS32_LE((uint64_t)(x) & 0xffffffff), \ BITS32_LE(((uint64_t)(x) >> 32) & 0xffffffff) /* Expected buffer contents for test_libipm_append_all_test */ static const unsigned char all_test_expected_buff[] = { BITS16_LE(LIBIPM_VERSION), BITS16_LE(73), /* Header : message length */ BITS16_LE(LIBIPM_FAC_TEST), BITS16_LE(TEST_MESSAGE_NO), BITS32_LE(0), /* ------------------- */ 'y', ALL_TEST_y_VALUE, 'b', ALL_TEST_b_VALUE, 'n', BITS16_LE(ALL_TEST_n_VALUE), 'q', BITS16_LE(ALL_TEST_q_VALUE), 'i', BITS32_LE(ALL_TEST_i_VALUE), 'u', BITS32_LE(ALL_TEST_u_VALUE), 'x', BITS64_LE(ALL_TEST_x_VALUE), 't', BITS64_LE(ALL_TEST_t_VALUE), /* String + terminator */ 's', ALL_TEST_s_VALUE, /* Fixed size block */ 'B', BITS16_LE(7) /* length */, ALL_TEST_B_VALUE }; /* Type used to map small test values (i.e. simple types that fit in an int) * to expected status codes if we try to output them for a given type */ struct int_test_value { int value; enum libipm_status expected_status; }; /***************************************************************************//** * Compares the data in a stream against an expected data block * * @param s Stream to check * @param expdata Expected data * @aram explen Expected data len */ static void check_stream_data_eq(const struct stream *s, const unsigned char *expected_data, unsigned int expected_len) { check_binary_data_eq((unsigned char *)s->data, (unsigned int)(s->end - s->data), expected_data, expected_len); } /***************************************************************************//** * Value checks for small types (i.e. those that fit in an 'int' */ static void test_small_type_values(char typechar, const struct int_test_value v[], unsigned int count) { unsigned int i; enum libipm_status status; char format[] = { typechar, '\0'}; for (i = 0 ; i < count; ++i) { status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, v[i].value); if (status != v[i].expected_status) { ck_abort_msg("Test value %d. Expected status %d, got %d", v[i].value, v[i].expected_status, status); } } } /***************************************************************************//** * Checks we can add a simple type right at the end of a buffer, but that * a buffer overflow is also detected if there's not enough space. */ static void test_append_at_end_of_message(char typechar, unsigned int wire_size) { char padding[LIBIPM_MAX_PAYLOAD_SIZE] = {0}; struct libipm_fsb desc; enum libipm_status status; const char format[] = {'B', typechar, '\0'}; /* Construct a descriptor for a binary object that fills most of * the output buffer, leaving just enough space for our type at the end. * Three bytes are needed for the binary descriptor overhead */ desc.data = padding; desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3 - wire_size; /* Check we're OK at the end of the buffer... */ status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0); ck_assert_int_eq(status, E_LI_SUCCESS); /* ..but if the value would overflow the end of the packet it's an error */ ++desc.datalen; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0); ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW); } /***************************************************************************//** * Appends all data types to a transport, and checks the binary data in * the output stream is as expected */ START_TEST(test_libipm_append_all_test) { ck_assert_ptr_ne(g_t_out, NULL); static char string[] = { ALL_TEST_s_VALUE }; static char binary[] = { ALL_TEST_B_VALUE }; struct libipm_fsb binary_desc = { (void *)binary, sizeof(binary) }; enum libipm_status status; status = libipm_msg_out_init( g_t_out, TEST_MESSAGE_NO, "ybnqiuxtsB", ALL_TEST_y_VALUE, ALL_TEST_b_VALUE, ALL_TEST_n_VALUE, ALL_TEST_q_VALUE, ALL_TEST_i_VALUE, ALL_TEST_u_VALUE, ALL_TEST_x_VALUE, ALL_TEST_t_VALUE, string, &binary_desc); ck_assert_int_eq(status, E_LI_SUCCESS); libipm_msg_out_mark_end(g_t_out); check_stream_data_eq( g_t_out->out_s, all_test_expected_buff, sizeof(all_test_expected_buff)); } END_TEST /***************************************************************************//** * Checks various send errors for 'y' */ START_TEST(test_libipm_send_y_type) { static const struct int_test_value test_values[] = { {0, E_LI_SUCCESS}, {255, E_LI_SUCCESS}, {-1, E_LI_BAD_VALUE}, {256, E_LI_BAD_VALUE}, {63336, E_LI_BAD_VALUE}, {2147483647, E_LI_BAD_VALUE} }; test_small_type_values('y', test_values, sizeof(test_values) / sizeof(test_values[0])); test_append_at_end_of_message('y', 2); } END_TEST /***************************************************************************//** * Checks various send errors for 'b' */ START_TEST(test_libipm_send_b_type) { static const struct int_test_value test_values[] = { {0, E_LI_SUCCESS}, {1, E_LI_SUCCESS}, {2, E_LI_BAD_VALUE}, {-1, E_LI_BAD_VALUE}, {256, E_LI_BAD_VALUE} }; test_small_type_values('b', test_values, sizeof(test_values) / sizeof(test_values[0])); test_append_at_end_of_message('b', 2); } END_TEST /***************************************************************************//** * Checks various send errors for 'n' */ START_TEST(test_libipm_send_n_type) { static const struct int_test_value test_values[] = { {-32768, E_LI_SUCCESS}, {32767, E_LI_SUCCESS}, {-32769, E_LI_BAD_VALUE}, {32768, E_LI_BAD_VALUE}, {2147483647, E_LI_BAD_VALUE} }; test_small_type_values('n', test_values, sizeof(test_values) / sizeof(test_values[0])); test_append_at_end_of_message('n', 3); } END_TEST /***************************************************************************//** * Checks various send errors for 'q' */ START_TEST(test_libipm_send_q_type) { static const struct int_test_value test_values[] = { {0, E_LI_SUCCESS}, {65535, E_LI_SUCCESS}, {-1, E_LI_BAD_VALUE}, {65536, E_LI_BAD_VALUE}, {2147483647, E_LI_BAD_VALUE} }; test_small_type_values('q', test_values, sizeof(test_values) / sizeof(test_values[0])); test_append_at_end_of_message('q', 3); } END_TEST /***************************************************************************//** * Checks various send errors for 'i' */ START_TEST(test_libipm_send_i_type) { #if SIZEOF_INT > 4 static const struct int_test_value test_values[] = { {-2147483648, E_LI_SUCCESS}, {2147483647, E_LI_SUCCESS}, {-2147483649, E_LI_BAD_VALUE}, {2147483648, E_LI_BAD_VALUE}, }; test_small_type_values('i', test_values, sizeof(test_values) / sizeof(test_values[0])); #endif test_append_at_end_of_message('i', 5); } END_TEST /***************************************************************************//** * Checks various send errors for 'u' */ START_TEST(test_libipm_send_u_type) { #if SIZEOF_INT > 4 static const struct int_test_value test_values[] = { {0, E_LI_SUCCESS}, {4294967296, E_LI_SUCCESS}, {-1, E_LI_BAD_VALUE}, {4294967297, E_LI_BAD_VALUE}, }; test_small_type_values('u', test_values, sizeof(test_values) / sizeof(test_values[0])); #endif test_append_at_end_of_message('u', 5); } END_TEST /***************************************************************************//** * Checks various send errors for 'x' */ START_TEST(test_libipm_send_x_type) { test_append_at_end_of_message('x', 9); } END_TEST /***************************************************************************//** * Checks various send errors for 't' */ START_TEST(test_libipm_send_t_type) { test_append_at_end_of_message('t', 9); } END_TEST /***************************************************************************//** * Checks various send errors for 's' */ START_TEST(test_libipm_send_s_type) { enum libipm_status status; /* The maximum string length would be LIBIPM_MAX_PAYLOAD_SIZE-2, as we * need one char for the 's' type marker, and another for the string * terminator */ /* Construct a string one character too long to fit in the buffer */ char str[LIBIPM_MAX_PAYLOAD_SIZE]; g_memset(str, 'A', sizeof(str)); str[sizeof(str) - 1] = '\0'; /* A write should overflow... */ status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str); ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW); /* .. but a string one character shorter should be OK */ str[sizeof(str) - 2] = '\0'; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str); ck_assert_int_eq(status, E_LI_SUCCESS); /* Check passing a NULL string doesn't crash the program */ status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", NULL); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); } END_TEST /***************************************************************************//** * Checks various send errors for 'B' */ START_TEST(test_libipm_send_B_type) { enum libipm_status status; char bin[LIBIPM_MAX_PAYLOAD_SIZE] = {0}; struct libipm_fsb desc; /* The maximum binary block length would be LIBIPM_MAX_PAYLOAD_SIZE - 3, * as we need one char for the 'B' type marker, and two for the length * * Construct a descriptor for a binary object that completely fills * the output buffer */ desc.data = bin; desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3; /* Check it fits in the buffer... */ status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc); ck_assert_int_eq(status, E_LI_SUCCESS); /* ..but one byte bigger, and it won't fit */ ++desc.datalen; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc); ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW); --desc.datalen; /* Check NULL pointers don't crash the library */ desc.data = NULL; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", NULL); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); } END_TEST /***************************************************************************//** * Checks send errors for unsupported and unimplemented types */ START_TEST(test_libipm_send_bad_types) { enum libipm_status status; enum libipm_status expected_status; char format[2] = {0}; char c; for (c = 0x1; c < 0x7f; ++c) { if (!isprint(c)) { continue; } if (g_strchr(g_supported_types, c) == NULL) { expected_status = E_LI_UNSUPPORTED_TYPE; } else if (g_strchr(g_unimplemented_types, c) != NULL) { expected_status = E_LI_UNIMPLEMENTED_TYPE; } else { continue; } format[0] = c; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO_STRING_NO, format, NULL); if (status != expected_status) { ck_abort_msg("Output char '%c'. Expected status %d, got %d", c, expected_status, status); } } } END_TEST /***************************************************************************//** * Checks message erase works as expected * * Also calls libipm_msg_out_append() which isn't exercised anywhere else */ START_TEST(test_libipm_send_msg_erase) { enum libipm_status status; const char *username = "username"; const char *password = "password"; status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL); ck_assert_int_eq(status, E_LI_SUCCESS); status = libipm_msg_out_append(g_t_out, "ss", username, password); ck_assert_int_eq(status, E_LI_SUCCESS); ck_assert_int_ne(does_stream_contain_string(g_t_out->out_s, password), 0); libipm_msg_out_erase(g_t_out); ck_assert_int_eq(does_stream_contain_string(g_t_out->out_s, password), 0); } END_TEST /***************************************************************************//** * Exercises codepaths that shouldn't be called (programming errors) */ START_TEST(test_libipm_send_programming_errors) { enum libipm_status status; status = libipm_msg_out_init(g_t_vanilla, TEST_MESSAGE_NO, NULL); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); status = libipm_msg_out_append(g_t_vanilla, "i", 0); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); libipm_msg_out_mark_end(g_t_vanilla); /* No status to check */ status = libipm_msg_out_simple_send(g_t_vanilla, TEST_MESSAGE_NO, "i", 0); ck_assert_int_eq(status, E_LI_PROGRAM_ERROR); } END_TEST /******************************************************************************/ Suite * make_suite_test_libipm_send_calls(void) { Suite *s; TCase *tc; s = suite_create("libipm_send"); tc = tcase_create("libipm_send"); suite_add_tcase(s, tc); tcase_add_test(tc, test_libipm_append_all_test); tcase_add_test(tc, test_libipm_send_y_type); tcase_add_test(tc, test_libipm_send_b_type); tcase_add_test(tc, test_libipm_send_n_type); tcase_add_test(tc, test_libipm_send_q_type); tcase_add_test(tc, test_libipm_send_i_type); tcase_add_test(tc, test_libipm_send_u_type); tcase_add_test(tc, test_libipm_send_x_type); tcase_add_test(tc, test_libipm_send_t_type); tcase_add_test(tc, test_libipm_send_s_type); tcase_add_test(tc, test_libipm_send_B_type); tcase_add_test(tc, test_libipm_send_y_type); tcase_add_test(tc, test_libipm_send_bad_types); tcase_add_test(tc, test_libipm_send_msg_erase); tcase_add_test(tc, test_libipm_send_programming_errors); return s; }