Я разрабатываю пользовательскую функцию для PostgreSQL на C. Эта функция будет использоваться как часть пользовательского агрегата. Я следую документации по Определяемым пользователем агрегатам и Функции языка C . Мне известна инфраструктура построения расширений, которую предоставляет установка PostgreSQL, задокументированная здесь , которая также предоставляет средства для тестирования расширения. Однако, чтобы облегчить разработку расширений PostgreSQL, мне было интересно, есть ли способ протестировать пользовательскую функцию, используя обычные методы модульного тестирования на Си.
Я пытаюсь использовать CMocka для моего модульного тестирования. Это осложняется макросами PG_FUNCTION_ARGS
и PG_FUNCTION_INFO_V1
из fmgr.h
, которые необходимы для функций C
, которые будут взаимодействовать с PostgreSQL. Эти макросы имеют тенденцию абстрагировать некоторые параметры обработки и в результате запутывают эту функциональность. В результате я испытываю трудности с вызовом моей пользовательской функции PostgreSQL в модульном тесте. У меня возникают ошибки, связанные с ожидаемыми типами параметров. Я не уверен, как вручную построить список параметров с помощью макросов для моей функции. Ниже приведены ошибки GCC, которые я получаю при попытке запустить мой модульный тест.
gcc -fprofile-arcs -ftest-coverage -I '/usr/include/postgresql/10/server' ./tests/test_max_pos_min_neg.c -o ./build/tests/test_max_pos_min_neg
./tests/test_max_pos_min_neg.c: In function ‘test_get_max_pos_min_neg’:
./tests/test_max_pos_min_neg.c:21:25: warning: passing argument 1 of ‘get_max_pos_min_neg’ from incompatible pointer type [-Wincompatible-pointer-types]
get_max_pos_min_neg((float4 *) init_cond, 10.0, -2.5, 7.5);
^
In file included from ./tests/test_max_pos_min_neg.c:6:0:
./tests/../src/max_pos_min_neg.h:8:7: note: expected ‘FunctionCallInfo {aka struct FunctionCallInfoData *}’ but argument is of type ‘float4 * {aka float *}’
Datum get_max_pos_min_neg(PG_FUNCTION_ARGS);
^~~~~~~~~~~~~~~~~~~
./tests/test_max_pos_min_neg.c:21:5: error: too many arguments to function ‘get_max_pos_min_neg’
get_max_pos_min_neg((float4 *) init_cond, 10.0, -2.5, 7.5);
^~~~~~~~~~~~~~~~~~~
In file included from ./tests/test_max_pos_min_neg.c:6:0:
./tests/../src/max_pos_min_neg.h:8:7: note: declared here
Datum get_max_pos_min_neg(PG_FUNCTION_ARGS);
^~~~~~~~~~~~~~~~~~~
./tests/test_max_pos_min_neg.c:24:5: warning: implicit declaration of function ‘assert_float_equal’; did you mean ‘assert_int_equal’? [-Wimplicit-function-declaration]
assert_float_equal(init_cond[0], 10.0, EPSILON);
^~~~~~~~~~~~~~~~~~
assert_int_equal
Makefile:59: recipe for target 'build/tests/test_max_pos_min_neg' failed
make: *** [build/tests/test_max_pos_min_neg] Error 1
Вот мой исходный код:
#include "postgres.h"
#include "fmgr.h"
#include "utils/array.h"
PG_MODULE_MAGIC;
Datum get_max_pos_min_neg(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_max_pos_min_neg);
// Computes the maximum positive and mininum negative sentiment scores.
Datum
get_max_pos_min_neg(PG_FUNCTION_ARGS)
{
ArrayType *state_array;
float4 *state;
float4 pos, neg, score;
state_array = PG_GETARG_ARRAYTYPE_P(0);
pos = PG_GETARG_FLOAT4(1);
neg = PG_GETARG_FLOAT4(2);
score = PG_GETARG_FLOAT4(3);
state = (float4 *) ARR_DATA_PTR(state_array);
if (state[2] < score)
{
state[0] = pos;
state[1] = neg;
state[2] = score;
}
if (score < state[5])
{
state[3] = pos;
state[4] = neg;
state[5] = score;
}
PG_RETURN_ARRAYTYPE_P(state);
}
Мой заголовочный файл:
#include "postgres.h"
#include "fmgr.h"
#include "utils/array.h"
Datum get_max_pos_min_neg(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_max_pos_min_neg);
Мой юнит-тест:
#include "../src/max_pos_min_neg.h"
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include "cmocka.h"
const float4 EPSILON = 0.001;
void
test_get_max_pos_min_neg(void **state)
{
(void) state; /* unused */
// This is the initial condition used by the SQL stored procedure
float4 init_cond[] = {0, 0, -1, 0, 0, 100};
get_max_pos_min_neg(init_cond, 10.0, -2.5, 7.5);
// init_cond should now be {10.0, -2.5, 7.5, 10.0, -2.5, 7.5}
assert_float_equal(init_cond[0], 10.0, EPSILON);
assert_float_equal(init_cond[1], -2.5, EPSILON);
assert_float_equal(init_cond[2], 7.5, EPSILON);
assert_float_equal(init_cond[3], 10.0, EPSILON);
assert_float_equal(init_cond[4], -2.5, EPSILON);
assert_float_equal(init_cond[5], 7.5, EPSILON);
}
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_get_max_pos_min_neg)
};
int
main(void)
{
return cmocka_run_group_tests(tests, NULL, NULL);
}
Будем весьма благодарны за любую помощь, которую вы можете оказать, чтобы протестировать функции языка C PostgreSQL вне PostgreSQL. Спасибо!