X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=t%2Futils%2Fdbi_test.c;h=59cd46bf4b9ad8f0b50ecfea9f2c4810d21be991;hb=f889d69c959224d94fce086172dc8fa97c5dea76;hp=57449bb546ee5fd61a6d8d092712b6032ca2a6f4;hpb=b5ae34b6be4eef0a3b85e4d830f6cd4c76f939e5;p=sysdb.git diff --git a/t/utils/dbi_test.c b/t/utils/dbi_test.c index 57449bb..59cd46b 100644 --- a/t/utils/dbi_test.c +++ b/t/utils/dbi_test.c @@ -33,12 +33,65 @@ #define TEST_MAGIC ((void *)0x1337) +/* + * private data-types + */ +typedef union { + long long integer; + double decimal; + const char *string; + time_t datetime; + struct { + size_t length; + const unsigned char *datum; + } binary; +} mock_data_t; + +typedef struct { + const char *name; + unsigned long long nrows; + unsigned long long current_row; + unsigned int nfields; + unsigned short *field_types; + char **field_names; +} mock_query_t; + /* * private variables */ static sdb_dbi_client_t *client; +/* + * mock queries + */ + +/* field definitions */ +static struct { + unsigned short field_types[1]; + char *field_names[1]; +} rows1[] = { + { { DBI_TYPE_INTEGER }, { "field0" }, }, +}; + +static mock_data_t golden_data[][1] = { + { { .integer = 1234 } }, + { { .integer = 2345 } }, + { { .integer = 3456 } }, + { { .integer = 4567 } }, + { { .integer = 5678 } }, +}; + +/* query definitions */ +static mock_query_t mock_queries[] = { + { "mockquery0", 5, 1, 0, NULL, NULL }, + { "mockquery1", 0, 0, 1, rows1[0].field_types, rows1[0].field_names }, + { "mockquery2", 1, 1, 1, rows1[0].field_types, rows1[0].field_names }, + { "mockquery3", 5, 1, 1, rows1[0].field_types, rows1[0].field_names }, +}; + +static mock_query_t *current_query = NULL; + /* * mocked functions */ @@ -90,7 +143,7 @@ dbi_conn_open(dbi_driver driver) return (dbi_conn)"mockconnection"; } /* dbi_conn_open */ -static int dbi_conn_connect_called = 0; +static unsigned long long dbi_conn_connect_called = 0; int dbi_conn_connect(dbi_conn conn) { @@ -114,60 +167,188 @@ dbi_conn_close(dbi_conn __attribute__((unused)) conn) return; } /* dbi_conn_close */ -static int dbi_conn_query_called = 0; +int +dbi_conn_error(dbi_conn conn, const char **errmsg) +{ + if ((! conn) || (strcmp((const char *)conn, "mockconnection"))) + return DBI_ERROR_BADOBJECT; + if (errmsg) + *errmsg = "mockerror"; + return DBI_ERROR_UNSUPPORTED; +} /* dbi_conn_error */ + +static unsigned long long dbi_conn_query_called = 0; dbi_result dbi_conn_query(dbi_conn conn, const char __attribute__((unused)) *statement) { + size_t i; + ++dbi_conn_query_called; if (strcmp((const char *)conn, "mockconnection")) return NULL; - return (dbi_result)"mockresult"; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { + if (!strcmp(mock_queries[i].name, statement)) { + current_query = &mock_queries[i]; + return (dbi_result)current_query; + } + } + return NULL; } /* dbi_conn_query */ unsigned long long dbi_result_get_numrows(dbi_result res) { - if (strcmp((const char *)res, "mockresult")) + mock_query_t *q = res; + if (! q) return DBI_ROW_ERROR; - return 5; + return q->nrows; } /* dbi_result_get_numrows */ -static int dbi_result_free_called = 0; -int -dbi_result_free(dbi_result res) -{ - ++dbi_result_free_called; - if (strcmp((const char *)res, "mockresult")) - return -1; - return 0; -} /* dbi_result_free */ - unsigned int dbi_result_get_numfields(dbi_result res) { - if (strcmp((const char *)res, "mockresult")) + mock_query_t *q = res; + if (! q) return DBI_FIELD_ERROR; - return 0; + return q->nfields; } /* dbi_result_get_numfields */ unsigned short -dbi_result_get_field_type_idx(dbi_result res, - unsigned int __attribute__((unused)) i) +dbi_result_get_field_type_idx(dbi_result res, unsigned int i) { - if (strcmp((const char *)res, "mockresult")) + mock_query_t *q = res; + if ((! q) || (i > q->nfields)) return DBI_TYPE_ERROR; - return DBI_TYPE_ERROR; + return q->field_types[i - 1]; } /* dbi_result_get_field_type_idx */ const char * -dbi_result_get_field_name(dbi_result res, - unsigned int __attribute__((unused)) i) +dbi_result_get_field_name(dbi_result res, unsigned int i) { - if (strcmp((const char *)res, "mockresult")) + mock_query_t *q = res; + if ((! q) || (i > q->nfields)) return NULL; - return NULL; + return q->field_names[i - 1]; } /* dbi_result_get_field_name */ +int +dbi_result_seek_row(dbi_result res, unsigned long long n) +{ + mock_query_t *q = res; + if ((! q) || (n > q->nrows)) + return 0; + + q->current_row = n; + return 1; +} /* dbi_result_seek_row */ + +static mock_data_t +get_golden_data(dbi_result res, unsigned int i) { + mock_query_t *q = res; + fail_unless(q != NULL, "dbi_result_get_*_idx() called with " + "NULL result data; expected valid result object"); + + /* this information is managed by seek_row and, thus, + * should never be invalid */ + fail_unless(q->current_row && q->current_row <= q->nrows, + "INTERNAL ERROR: current row out of range"); + + fail_unless(i && i <= q->nfields, + "dbi_result_get_*_idx() called with index out of range; " + "got: %u; expected [1, %u]", i, q->nfields); + return golden_data[q->current_row - 1][i - 1]; +} /* get_golden_data */ + +long long +dbi_result_get_longlong_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_INTEGER, + "dbi_result_get_longlong_idx() called for non-integer " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).integer; +} /* dbi_result_get_longlong_idx */ + +double +dbi_result_get_double_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DECIMAL, + "dbi_result_get_double_idx() called for non-decimal " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).decimal; +} /* dbi_result_get_double_idx */ + +const char * +dbi_result_get_string_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING, + "dbi_result_get_string_idx() called for non-string " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).string; +} /* dbi_result_get_string_idx */ + +time_t +dbi_result_get_datetime_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DATETIME, + "dbi_result_get_datetime_idx() called for non-datetime " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).datetime; +} /* dbi_result_get_datetime_idx */ + +size_t +dbi_result_get_field_length_idx(dbi_result res, unsigned int i) +{ + /* this will check if the parameters are valid */ + get_golden_data(res, i); + + switch (current_query->field_types[i - 1]) { + case DBI_TYPE_INTEGER: + return sizeof(long long); + break; + case DBI_TYPE_DECIMAL: + return sizeof(double); + break; + case DBI_TYPE_STRING: + return strlen(get_golden_data(res, i).string) + 1; + break; + case DBI_TYPE_DATETIME: + return sizeof(time_t); + break; + case DBI_TYPE_BINARY: + return get_golden_data(res, i).binary.length; + break; + } + + fail("INTERNAL ERROR: dbi_result_get_field_length_idx() " + "called for unexpected field type %u", + current_query->field_types[i - 1]); + return 0; +} /* dbi_result_get_field_length_idx */ + +const unsigned char * +dbi_result_get_binary_idx(dbi_result res, unsigned int i) +{ + fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY, + "dbi_result_get_binary_idx() called for non-binary " + "column type %u", current_query->field_types[i - 1]); + return get_golden_data(res, i).binary.datum; +} /* dbi_result_get_binary_idx */ + +static unsigned long long dbi_result_free_called = 0; +int +dbi_result_free(dbi_result res) +{ + mock_query_t *q = res; + + ++dbi_result_free_called; + if (! q) + return -1; + + current_query = NULL; + return 0; +} /* dbi_result_free */ + /* * private helper functions */ @@ -195,23 +376,84 @@ teardown(void) client = NULL; } /* teardown */ -static int test_query_callback_called = 0; +static unsigned long long test_query_callback_called = 0; static int test_query_callback(sdb_dbi_client_t *c, size_t n, sdb_data_t *data, sdb_object_t *user_data) { + size_t i; + ++test_query_callback_called; fail_unless(c == client, "query callback received unexpected client = %p; " "expected: %p", c, client); - fail_unless(n == 0, - "query callback received n = %i; expected: 0", n); - fail_unless(data == NULL, - "query callback received data = %p; expected: NULL", data); + fail_unless(n == current_query->nfields, + "query callback received n = %i; expected: %i", + n, current_query->nfields); + fail_unless(data != NULL, + "query callback received data = NULL; expected: valid data"); fail_unless(user_data == TEST_MAGIC, "query callback received user_data = %p; expected: %p", user_data, TEST_MAGIC); + + for (i = 0; i < n; ++i) { + int expected_type = DBI_TYPE_TO_SC(current_query->field_types[i]); + mock_data_t expected_data; + + fail_unless((int)data[i].type == expected_type, + "query callback received unexpected type %i for " + "column %zu; expected: %i", data[i].type, i, + expected_type); + + expected_data = golden_data[current_query->current_row - 1][i]; + switch (expected_type) { + case SDB_TYPE_INTEGER: + fail_unless(data[i].data.integer == expected_data.integer, + "query callback received unexpected data %lli " + "for column %zu; expected: %lli", + data[i].data.integer, i, expected_data.integer); + break; + case SDB_TYPE_DECIMAL: + fail_unless(data[i].data.decimal == expected_data.decimal, + "query callback received unexpected data %g " + "for column %zu; expected: %g", + data[i].data.decimal, i, expected_data.decimal); + break; + case SDB_TYPE_STRING: + fail_unless(data[i].data.string == expected_data.string, + "query callback received unexpected data %s " + "for column %zu; expected: %s", + data[i].data.string, i, expected_data.string); + break; + case SDB_TYPE_DATETIME: + fail_unless(data[i].data.datetime + == SECS_TO_SDB_TIME(expected_data.datetime), + "query callback received unexpected data "PRIscTIME + " for column %zu; expected: "PRIscTIME, + data[i].data.integer, i, + SECS_TO_SDB_TIME(expected_data.integer)); + break; + case SDB_TYPE_BINARY: + fail_unless(data[i].data.binary.length == + expected_data.binary.length, + "query callback received unexpected " + "binary data length %zu for column %zu; " + "expected: %lli", data[i].data.binary.length, i, + expected_data.binary.length); + fail_unless(data[i].data.binary.datum == + expected_data.binary.datum, + "query callback received unexpected binary data %p " + "for column %zu; expected: %p", + data[i].data.binary.datum, i, + expected_data.binary.datum); + break; + default: + fail("INTERNAL ERROR: query callback received " + "unknown type %i for column %zu", + expected_type, i); + } + } return 0; } /* test_query_callback */ @@ -242,20 +484,23 @@ START_TEST(test_client_check_conn) "sdb_dbi_client_check_conn() called dbi_conn_connect %i times; " "expected: 1", dbi_conn_connect_called); + dbi_conn_connect_called = 0; check = sdb_dbi_client_check_conn(client); fail_unless(check == 0, "sdb_dbi_client_check_conn() = %i; expected: 0", check); /* should not reconnect */ - fail_unless(dbi_conn_connect_called == 1, + fail_unless(dbi_conn_connect_called == 0, "sdb_dbi_client_check_conn() called dbi_conn_connect %i time(s); " - "expected: 0", dbi_conn_connect_called - 1); + "expected: 0", dbi_conn_connect_called); } END_TEST START_TEST(test_exec_query) { - int check = sdb_dbi_exec_query(client, "mockquery", test_query_callback, + size_t i; + + int check = sdb_dbi_exec_query(client, "mockquery0", test_query_callback, /* user_data = */ TEST_MAGIC, /* n = */ 0); /* not connected yet */ fail_unless(check < 0, @@ -263,22 +508,37 @@ START_TEST(test_exec_query) connect(); - check = sdb_dbi_exec_query(client, "mockquery", test_query_callback, - /* user_data = */ TEST_MAGIC, /* n = */ 0); - fail_unless(check == 0, - "sdb_dbi_exec_query() = %i; expected: 0", check); - - fail_unless(dbi_conn_query_called == 1, - "sdb_dbi_exec_query() called dbi_conn_query %i times; " - "expected: 1", dbi_conn_query_called); - fail_unless(test_query_callback_called == 0, - "sdb_dbi_exec_query() did not call the registered callback " - "for each result row; got %i call%s; expected: 0", - test_query_callback_called, - (test_query_callback_called == 1) ? "" : "s"); - - fail_unless(dbi_result_free_called == 1, - "sdb_dbi_exec_query() did not free the query result object"); + for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) { + mock_query_t *q = &mock_queries[i]; + + unsigned long long expected_callback_calls = 0; + + dbi_conn_query_called = 0; + test_query_callback_called = 0; + dbi_result_free_called = 0; + + check = sdb_dbi_exec_query(client, q->name, test_query_callback, + /* user_data = */ TEST_MAGIC, /* n = */ (int)q->nfields, + SDB_TYPE_INTEGER); + fail_unless(check == 0, + "sdb_dbi_exec_query() = %i; expected: 0", check); + + fail_unless(dbi_conn_query_called == 1, + "sdb_dbi_exec_query() called dbi_conn_query %i times; " + "expected: 1", dbi_conn_query_called); + + if (q->nfields) + expected_callback_calls = q->nrows; + + fail_unless(test_query_callback_called == expected_callback_calls, + "sdb_dbi_exec_query() did not call the registered callback " + "for each result row; got %i call%s; expected: 0", + test_query_callback_called, + (test_query_callback_called == 1) ? "" : "s"); + + fail_unless(dbi_result_free_called == 1, + "sdb_dbi_exec_query() did not free the query result object"); + } } END_TEST