| /* |
| * This API is subset plunit lib with http://www.apollo-pro.com/help/pl_unit_assertions.htm |
| * |
| */ |
| |
| #include "postgres.h" |
| #include "funcapi.h" |
| #include "parser/parse_oper.h" |
| #include "utils/builtins.h" |
| #include "orafunc.h" |
| #include "builtins.h" |
| |
| PG_FUNCTION_INFO_V1(plunit_assert_true); |
| PG_FUNCTION_INFO_V1(plunit_assert_true_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_false); |
| PG_FUNCTION_INFO_V1(plunit_assert_false_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_null); |
| PG_FUNCTION_INFO_V1(plunit_assert_null_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_null); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_null_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_equals); |
| PG_FUNCTION_INFO_V1(plunit_assert_equals_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_equals_range); |
| PG_FUNCTION_INFO_V1(plunit_assert_equals_range_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_equals); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_equals_message); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range); |
| PG_FUNCTION_INFO_V1(plunit_assert_not_equals_range_message); |
| PG_FUNCTION_INFO_V1(plunit_fail); |
| PG_FUNCTION_INFO_V1(plunit_fail_message); |
| |
| static bool assert_equals_base(FunctionCallInfo fcinfo); |
| static bool assert_equals_range_base(FunctionCallInfo fcinfo); |
| static char *assert_get_message(FunctionCallInfo fcinfo, int nargs, char *default_message); |
| |
| |
| /**************************************************************** |
| * plunit.assert_true |
| * plunit.assert_true_message |
| * |
| * Syntax: |
| * PROCEDURE assert_true(condition boolean, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that the condition is true. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default message |
| * is displayed. |
| * |
| ****************************************************************/ |
| Datum |
| plunit_assert_true(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_true_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_true_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 2, "plunit.assert_true exception"); |
| bool condition = PG_GETARG_BOOL(0); |
| |
| if (PG_ARGISNULL(0) || !condition) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_true)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| /**************************************************************** |
| * plunit.assert_false |
| * plunit.assert_false_message |
| * |
| * Syntax: |
| * PROCEDURE assert_false(condition boolean, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that the condition is false. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default message |
| * is displayed. |
| * |
| ****************************************************************/ |
| Datum |
| plunit_assert_false(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_false_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_false_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 2, "plunit.assert_false exception"); |
| bool condition = PG_GETARG_BOOL(0); |
| |
| if (PG_ARGISNULL(0) || condition) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_false)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| /**************************************************************** |
| * plunit.assert_null |
| * plunit.assert_null_message |
| * |
| * Syntax: |
| * PROCEDURE assert_null(actual anyelement, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that the actual is null. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default message |
| * is displayed. |
| * |
| ****************************************************************/ |
| Datum |
| plunit_assert_null(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_null_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_null_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 2, "plunit.assert_null exception"); |
| |
| if (!PG_ARGISNULL(0)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_null)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| /**************************************************************** |
| * plunit.assert_not_null |
| * plunit.assert_not_null_message |
| * |
| * Syntax: |
| * PROCEDURE assert_not_null(actual anyelement, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that the actual isn't null. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default message |
| * is displayed. |
| * |
| ****************************************************************/ |
| Datum |
| plunit_assert_not_null(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_not_null_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_not_null_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 2, "plunit.assert_not_null exception"); |
| |
| if (PG_ARGISNULL(0)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_not_null)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| |
| /**************************************************************** |
| * plunit.assert_equals |
| * plunit.assert_equals_message |
| * plunit.assert_equals_range |
| * plunit.assert_equals_range_message |
| * |
| * Syntax: |
| * PROCEDURE assert_equals(expected anyelement,actual anyelement, |
| * message varchar default ''); |
| * PROCEDURE assert_equals(expected double precision, actual double precision, |
| * range double precision, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that expected and actual are equal. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default |
| * message is displayed. |
| * Asserts that expected and actual are within the specified range. |
| * The optional message will be displayed if the assertion fails. |
| * If not supplied, a default message is displayed. |
| * |
| ****************************************************************/ |
| static char * |
| assert_get_message(FunctionCallInfo fcinfo, int nargs, char *message) |
| { |
| char *result; |
| |
| if (PG_NARGS() == nargs) |
| { |
| text *msg; |
| |
| if (PG_ARGISNULL(nargs - 1)) |
| ereport(ERROR, |
| (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| errmsg("message is NULL"), |
| errdetail("Message may not be NULL."))); |
| |
| msg = PG_GETARG_TEXT_P(nargs - 1); |
| result = text_to_cstring(msg); |
| } |
| else |
| result = message; |
| |
| return result; |
| } |
| |
| |
| static bool |
| assert_equals_base(FunctionCallInfo fcinfo) |
| { |
| Datum value1 = PG_GETARG_DATUM(0); |
| Datum value2 = PG_GETARG_DATUM(1); |
| Oid *ptr; |
| |
| ptr = (Oid *) fcinfo->flinfo->fn_extra; |
| if (ptr == NULL) |
| { |
| Oid valtype = get_fn_expr_argtype(fcinfo->flinfo, 0); |
| Oid eqopfcid; |
| |
| if (!OidIsValid(valtype)) |
| elog(ERROR, "could not determine data type of input"); |
| |
| eqopfcid = equality_oper_funcid(valtype); |
| |
| if (!OidIsValid(eqopfcid)) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("unknown equal operand for datatype"))); |
| |
| /* First time calling for current query: allocate storage */ |
| fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, |
| sizeof(Oid)); |
| ptr = (Oid *) fcinfo->flinfo->fn_extra; |
| *ptr = eqopfcid; |
| } |
| |
| return DatumGetBool(OidFunctionCall2(*ptr, value1, value2)); |
| } |
| |
| Datum |
| plunit_assert_equals(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_equals_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_equals_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 3, "plunit.assert_equal exception"); |
| |
| /* skip all tests for NULL value */ |
| if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_equals)."))); |
| |
| if (!assert_equals_base(fcinfo)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_equals)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| Datum |
| plunit_assert_equals_range(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_equals_range_message(fcinfo); |
| } |
| |
| static bool |
| assert_equals_range_base(FunctionCallInfo fcinfo) |
| { |
| float8 expected_value; |
| float8 actual_value; |
| float8 range_value; |
| |
| range_value = PG_GETARG_FLOAT8(2); |
| if (range_value < 0) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("cannot set range to negative number"))); |
| |
| expected_value = PG_GETARG_FLOAT8(0); |
| actual_value = PG_GETARG_FLOAT8(1); |
| |
| return fabs(expected_value - actual_value) < range_value; |
| } |
| |
| Datum |
| plunit_assert_equals_range_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 4, "plunit.assert_equal exception"); |
| |
| /* skip all tests for NULL value */ |
| if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_equals)."))); |
| |
| if (!assert_equals_range_base(fcinfo)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_equals)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| |
| /**************************************************************** |
| * plunit.assert_not_equals |
| * plunit.assert_not_equals_message |
| * plunit.assert_not_equals_range |
| * plunit.assert_not_equals_range_message |
| * |
| * Syntax: |
| * PROCEDURE assert_not_equals(expected anyelement,actual anyelement, |
| * message varchar default ''); |
| * PROCEDURE assert_not_equals(expected double precision, expected double precision, |
| * range double precision, message varchar default ''); |
| * |
| * Purpouse: |
| * Asserts that expected and actual are equal. The optional message will be |
| * displayed if the assertion fails. If not supplied, a default |
| * message is displayed. |
| * Asserts that expected and actual are within the specified range. |
| * The optional message will be displayed if the assertion fails. |
| * If not supplied, a default message is displayed. |
| * |
| ****************************************************************/ |
| Datum |
| plunit_assert_not_equals(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_not_equals_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_not_equals_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 3, "plunit.assert_not_equal exception"); |
| |
| /* skip all tests for NULL value */ |
| if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_not_equals)."))); |
| |
| if (assert_equals_base(fcinfo)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s",message), |
| errdetail("Plunit.assertation fails (assert_not_equals)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| Datum |
| plunit_assert_not_equals_range(PG_FUNCTION_ARGS) |
| { |
| return plunit_assert_not_equals_range_message(fcinfo); |
| } |
| |
| Datum |
| plunit_assert_not_equals_range_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 3, "plunit.assert_not_equal exception"); |
| |
| /* skip all tests for NULL value */ |
| if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s", message), |
| errdetail("Plunit.assertation fails (assert_not_equals)."))); |
| |
| if (assert_equals_range_base(fcinfo)) |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s", message), |
| errdetail("Plunit.assertation fails (assert_not_equals)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |
| /**************************************************************** |
| * plunit.fail |
| * plunit.fail_message |
| * |
| * Syntax: |
| * PROCEDURE fail(message varchar default ''); |
| * |
| * Purpouse: |
| * Fail can be used to cause a test procedure to fail |
| * immediately using the supplied message. |
| * |
| ****************************************************************/ |
| |
| Datum |
| plunit_fail(PG_FUNCTION_ARGS) |
| { |
| return plunit_fail_message(fcinfo); |
| } |
| |
| Datum |
| plunit_fail_message(PG_FUNCTION_ARGS) |
| { |
| char *message = assert_get_message(fcinfo, 1, "plunit.assert_fail exception"); |
| |
| ereport(ERROR, |
| (errcode(ERRCODE_CHECK_VIOLATION), |
| errmsg("%s", message), |
| errdetail("Plunit.assertation (assert_fail)."))); |
| |
| PG_RETURN_VOID(); |
| } |
| |