diff --git a/contrib/babelfishpg_unit/Makefile b/contrib/babelfishpg_unit/Makefile new file mode 100644 index 0000000000..3cb4d58915 --- /dev/null +++ b/contrib/babelfishpg_unit/Makefile @@ -0,0 +1,12 @@ +MODULE_big = babelfishpg_unit +EXTENSION = babelfishpg_unit # the extension's name +DATA = babelfishpg_unit--1.0.0.sql # script file to install +OBJS = $(SRCS:.c=.o) # object files + + # source code files +SRCS = babelfishpg_unit.c test_money.c \ + +# for posgres build +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) \ No newline at end of file diff --git a/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql b/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql new file mode 100644 index 0000000000..9ef1d6f300 --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit--1.0.0.sql @@ -0,0 +1,16 @@ +--complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION babelfishpg_unit" to load this file. \quit + + +-- Invoke all tests +CREATE OR REPLACE FUNCTION babelfishpg_unit_run_tests() RETURNS +TABLE(TEST_NAME text, STATUS text, "runtime(µs)" bigint, ENABLED text) +as 'babelfishpg_unit', 'babelfishpg_unit_run_tests' +LANGUAGE C IMMUTABLE STRICT; + + +-- Invoke specific tests by passing test_name, cateogry_name or JIRA associated with +CREATE OR REPLACE FUNCTION babelfishpg_unit_run_tests(VARIADIC name text[]) RETURNS +TABLE(TEST_NAME text, STATUS text, "runtime(µs)" bigint, ENABLED text) +as 'babelfishpg_unit', 'babelfishpg_unit_run_tests' +LANGUAGE C IMMUTABLE STRICT; \ No newline at end of file diff --git a/contrib/babelfishpg_unit/babelfishpg_unit.c b/contrib/babelfishpg_unit/babelfishpg_unit.c new file mode 100644 index 0000000000..c870a39b00 --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit.c @@ -0,0 +1,377 @@ +#include "babelfishpg_unit.h" + +Datum babelfishpg_unit_run_tests(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(babelfishpg_unit_run_tests); + + +#define NCOLS (4) + +#define TEST_NAME_COLUMN 0 +#define STATUS_NAME_COLUMN (TEST_NAME_COLUMN + 1) +#define RUNTIME_NAME_COLUMN (STATUS_NAME_COLUMN + 1) +#define ENABLED_NAME_COLUMN (RUNTIME_NAME_COLUMN + 1) + +#define TEXT_HEADER_SIZE (28) + +typedef struct +{ + TestResult *(*test_func)(); + bool enabled; + char test_func_name[MAX_TEST_NAME_LENGTH]; + char category[MAX_TEST_NAME_LENGTH]; +} TestInfo; + +typedef struct +{ + bool nulls[NCOLS]; + TupleDesc tupledesc; + int test_run; + int current_test; + int num_tests; + + /* + * When running categories or a list of tests ensure we don't run any test + * more than once. Simply maintain an array of booleans that indicate + * a test has been already included in this test run to prevent duplicates. + * It has 1-1 mapping to the tests array just below. + */ + short *test_included; +} StateInfo; + + +static char* PASS = "pass"; +static char* FAIL = "fail"; +static char* NOT_RUN = "no run"; +static char* ENABLED = "enabled"; +static char* DISABLED = "disabled"; + + +/* + * Add test metadata here. + * + * . Add function declaration + * . Add row to tests array that identifies your test containing: + * . Pointer to test function (takes no params and returns a TestResult pointer + * . enabled flag, true to enable + * . Human readable test name + * . Human readable category, tests can then be run by category, name, or all + * + * . Update for test declarations are needed in babelfishpg_unit.h + * . New tests can be added in their own file or an existing file if applicable. If + * adding to a new file, update Makefile to reference the new source file. + */ + + +TestInfo tests[]= +{ + {&test_int4_fixeddecimal_ge, true, "GreaterThanOrEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_le, true, "LesserThanOrEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_ne, true, "NotEqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_eq, true, "EqualToCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_lt, true, "LesserThanCheck_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_int4_fixeddecimal_cmp, true, "Comparison_INT4_FIXEDDECIMAL", "babelfish_money_datatype"}, + {&test_fixeddecimalum, true, "FIXEDDECIMALUM", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_ge, true, "GreaterThanOrEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_le, true, "LesserThanOrEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_gt, true, "GreaterThanCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_ne, true, "NotEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, + {&test_fixeddecimal_int2_cmp, true, "Comparison_FIXEDDECIMAL_INT2", "babelfish_money_datatype"}, +}; + + +// Forward declarations +TestResult *run_test(TestInfo *test); +void setNull(StateInfo *state, bool message); +void calc_num_tests(StateInfo *state); +void calc_tests_for_run(StateInfo *state, int arg_size, VarChar **args); +int calc_next_test(StateInfo *state, int position); + + +/* + * run_test + * + * Run a single test as specified by TestInfo. Return the result of + * running the test (TestResult) which contains pass/fail, runtime, and + * if supplied by the test a message concerning the test run. + * + */ +TestResult * +run_test(TestInfo *test) +{ + return test->test_func(); +} + + +/* + * setNull + * + * When returning a row or test run it is necessary to specify which columns + * are null. Only the message column can be null so if the message parameter + * is true, that column is set to be null + * + */ +void +setNull(StateInfo *state, bool message) +{ + int i; + for(i=0; inulls[i] = false; +} + + +/* + * calc_num_tests + * + * Calculate the total number of tests available to run, store + * it in the supplied state. + */ +void +calc_num_tests(StateInfo *state) +{ + state->num_tests = sizeof(tests) / sizeof(TestInfo); +} + + +/* + * calc_tests_for_run + * + * Given a list of test names or test categories scan the list + * of all tests and mark an array the same length as the list + * of all tests with those to run. + */ +void +calc_tests_for_run(StateInfo *state, int argc, text **argv) +{ + int i, j; + text **arg_ptr = argv; + + if (argc == 0) + { + memset(state->test_included, 1, state->num_tests * sizeof(short)); + return; + } + + + for (i=0; inum_tests; j++) + { + if ((strcmp(tests[j].test_func_name, testname) == 0) || + (strcmp(tests[j].category, testname) == 0)) { + state->test_included[j] = true; + } + } + pfree(testname); + } +} + + +/* + * calc_next_test + * + * Pass in the position in the test included array and start + * searching forward from position inclusive until end of array + * or until a test to run is found. If a test is found return + * that position, otherwise return the number of tests indicating + * we are beyond the range of tests and therefore there is no + * tests remaining to be run. + */ +int +calc_next_test(StateInfo *state, int position) +{ + if (position >= state->num_tests) + return state->num_tests; + + + while (state->test_included[position] == false) + { + if (position >= state->num_tests) + { + state->current_test = state->num_tests; + return state->num_tests; + } + + position++; + } + + return position; +} + + +/* + * Some global declarations for creating a logfile after each test run + */ +char filename[200]; +FILE *file; +struct tm *timenow; +time_t current; + +Datum +babelfishpg_unit_run_tests(PG_FUNCTION_ARGS) +{ + FuncCallContext *fctx; + TupleDesc tupledesc; + Datum result; + Datum values[NCOLS]; + HeapTuple tuple; + MemoryContext mctx; + TestInfo *test; + TestResult *tr; + int nargs = PG_NARGS(); + text **args = NULL; + text **arg_ptr; + int i; + StateInfo* state; + char *message; + ArrayType *arr; + Datum *decontructed_arr; + bool *nulls; + size_t message_size = 0; + + if (SRF_IS_FIRSTCALL()) + { + + /* + * First call, allocate state needed for multiple + * calls to this routine. + */ + fctx = SRF_FIRSTCALL_INIT(); + mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx); + state = palloc0(sizeof(StateInfo)); + + calc_num_tests(state); + + /* + * Based on input parameters calculate tests to + * run. Run all if no parameters provided, default + * case + */ + + if (nargs > 0) + { + /* + * Deconstructed the array for accessing the args passed to the function and + * Storing the content of parameters in 'args' + */ + arr = PG_GETARG_ARRAYTYPE_P(0); + deconstruct_array(arr, TEXTOID, -1, false, TYPALIGN_INT, &decontructed_arr, &nulls, &nargs); + + args = palloc(nargs * sizeof(text *)); + for (i=0; itest_included = palloc0(state->num_tests * sizeof(short)); + calc_tests_for_run(state, nargs, args); + state->current_test = calc_next_test(state, 0); + if (args != NULL) + pfree(args); + + /* + * Create the tuple returned to the caller. Set up the + * table with the specified columns below. This only + * needs to be setup on the first call. + */ + tupledesc = CreateTemplateTupleDesc(NCOLS); + TupleDescInitEntry(tupledesc, (AttrNumber) TEST_NAME_COLUMN+1, "TEST_NAME", TEXTOID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) STATUS_NAME_COLUMN+1, "STATUS", TEXTOID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) RUNTIME_NAME_COLUMN+1, "RUNTIME", INT8OID, -1, 0); + TupleDescInitEntry(tupledesc, (AttrNumber) ENABLED_NAME_COLUMN+1, "ENABLED", TEXTOID, -1, 0); + + state->tupledesc = BlessTupleDesc(tupledesc); + fctx->user_fctx = state; + MemoryContextSwitchTo(mctx); + + /* + * Creating a log file with current date and time in logfile folder present within this extension + */ + current = time(NULL); + timenow = gmtime(¤t); + strftime(filename, sizeof(filename), "../../babelfish_extensions/contrib/babelfishpg_unit/log_files/UNIT_%Y%m%d_%H%M%S.log", timenow); + } + + /* + * Retrieve State Info needed to run the actual test + */ + fctx = SRF_PERCALL_SETUP(); + state = fctx->user_fctx; + tupledesc = state->tupledesc; + + if (state->current_test < state->num_tests) { + instr_time start, end; + test = &tests[state->current_test]; + setNull(state, false); + INSTR_TIME_SET_CURRENT(start); + + /* + * If enabled actually run the test + */ + if (test->enabled) + { + tr = run_test(test); + state->test_run++; + } else + { + tr = palloc0(sizeof(TestResult)); + } + + /* + * Compute timing information and if a message was returned and + * set message column to null if it is null message + */ + INSTR_TIME_SET_CURRENT(end); + + tr->run_time = INSTR_TIME_GET_MICROSEC(end) - INSTR_TIME_GET_MICROSEC(start); + if (tr->message == NULL) + setNull(state, true); + + /* + * Set the information for a row of data indicating test failure or pass + */ + values[TEST_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->test_func_name)); + values[STATUS_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->enabled ? + (tr->result ? PASS : FAIL) : NOT_RUN)); + values[RUNTIME_NAME_COLUMN] = PointerGetDatum(tr->run_time); + values[ENABLED_NAME_COLUMN] = PointerGetDatum(cstring_to_text(test->enabled ? ENABLED : DISABLED)); + tuple = heap_form_tuple(state->tupledesc, values, state->nulls); + result = HeapTupleGetDatum(tuple); + + + /* + * Writing the content into the log file + * Content will be test_func_name, result of test, error message if any + */ + message_size = strlen(test->test_func_name) + strlen(tr->result ? "PASSED" : "FAILED") + strlen(tr->message) + strlen(tr->testcase_message) + 10; + message = palloc(message_size); + snprintf(message, message_size, "%s, %s%s%s", test->test_func_name, tr->result ? "PASSED" : "FAILED", tr->message, tr->testcase_message); + + file = fopen(filename, "a+"); + fprintf(file, "%s\n\n\n", message); + fclose(file); + + pfree(message); + + /* + * Set the state to run the next test on the next function call + */ + state->current_test = calc_next_test(state, state->current_test + 1); + + pfree(tr); + + SRF_RETURN_NEXT(fctx, result); + } + + /* + * All the requested tests have been processed, do final return + */ + pfree(state->test_included); + pfree(state); + SRF_RETURN_DONE(fctx); +} + diff --git a/contrib/babelfishpg_unit/babelfishpg_unit.h b/contrib/babelfishpg_unit/babelfishpg_unit.h new file mode 100644 index 0000000000..9330b70f25 --- /dev/null +++ b/contrib/babelfishpg_unit/babelfishpg_unit.h @@ -0,0 +1,69 @@ +#include "postgres.h" +#include "fmgr.h" +#include "utils/builtins.h" +#include "utils/elog.h" +#include +#include "access/htup_details.h" +#include "access/clog.h" +#include "catalog/pg_type.h" +#include "funcapi.h" +#include "access/rmgr.h" +#include "access/xlog_internal.h" +#include "storage/backendid.h" +#include "storage/smgr.h" + +#include "utils/memutils.h" + +#define MAX_TEST_NAME_LENGTH (256) +#define MAX_TEST_MESSAGE_LENGTH (2048) + +typedef struct +{ + bool result; + char message[MAX_TEST_MESSAGE_LENGTH]; + char testcase_message[MAX_TEST_MESSAGE_LENGTH]; + uint64 run_time; +} TestResult; + + +#define TEST_ASSERT(condition, pResult) \ +do { \ + if(pResult->result == false){ \ + snprintf((pResult)->message, \ + MAX_TEST_MESSAGE_LENGTH, \ + ", Test assertion '%s' failed at %s:%d", \ + #condition, __FILE__, __LINE__); \ + } \ +} while (0) + + +#define TEST_ASSERT_TESTCASE(condition, test_case, exp, obt, pResult) \ +do { \ + if (!(condition)) { \ + snprintf((pResult)->testcase_message + strlen((pResult)->testcase_message), \ + MAX_TEST_MESSAGE_LENGTH - strlen((pResult)->testcase_message), \ + "\nTest Case '%s' failed, Expected: %s Obtained: %s", \ + test_case, exp, obt); \ + (pResult)->result = false; \ + } \ + else{ \ + snprintf((pResult)->testcase_message + strlen((pResult)->testcase_message), \ + MAX_TEST_MESSAGE_LENGTH - strlen((pResult)->testcase_message), \ + "\nTest Case '%s' passed, Expected: %s Obtained: %s", \ + test_case, exp, obt); \ + } \ +} while (0) + + +extern TestResult *test_int4_fixeddecimal_ge(void); +extern TestResult *test_int4_fixeddecimal_le(void); +extern TestResult *test_int4_fixeddecimal_ne(void); +extern TestResult *test_int4_fixeddecimal_eq(void); +extern TestResult *test_int4_fixeddecimal_lt(void); +extern TestResult *test_int4_fixeddecimal_cmp(void); +extern TestResult *test_fixeddecimalum(void); +extern TestResult *test_fixeddecimal_int2_ge(void); +extern TestResult *test_fixeddecimal_int2_le(void); +extern TestResult *test_fixeddecimal_int2_gt(void); +extern TestResult *test_fixeddecimal_int2_ne(void); +extern TestResult *test_fixeddecimal_int2_cmp(void); diff --git a/contrib/babelfishpg_unit/log_files/.gitignore b/contrib/babelfishpg_unit/log_files/.gitignore new file mode 100644 index 0000000000..86d0cb2726 --- /dev/null +++ b/contrib/babelfishpg_unit/log_files/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/contrib/babelfishpg_unit/test_money.c b/contrib/babelfishpg_unit/test_money.c new file mode 100644 index 0000000000..84bd6691ec --- /dev/null +++ b/contrib/babelfishpg_unit/test_money.c @@ -0,0 +1,415 @@ +#include "babelfishpg_unit.h" +#include "../babelfishpg_money/fixeddecimal.c" + +/* + * These are the test functions which returns a TestResult structure containing the result of the test. + * We will expect some result and the obtained result is compared with the expected result using the TEST_ASSERT and TEST_ASSERT_TESTCASE macro. + * If the obtained result matches the expected result, the test passes; otherwise, it fails. + */ + +TestResult* +test_int4_fixeddecimal_ge(void) +{ + /* + * This function checks whether val1 is greater than or equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] >= val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_le(void) +{ + /* + * This function checks whether val1 is lesser than or equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] <= val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_le, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_ne(void) +{ + /* + * This function checks whether val1 is not equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] != val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_ne, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_eq(void) +{ + /* + * This function checks whether val1 is equal to val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] == val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_eq, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_lt(void) +{ + /* + * This function checks whether val1 is less than val2 or not. + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] < val2[i]); + Datum temp = DirectFunctionCall2(int4_fixeddecimal_lt, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_int4_fixeddecimal_cmp(void) +{ + /* + * This function compares val1 and val2. + * val1 > val2 then result will be 1 + * val1 == val2 then result will be 0 + * val1 < val2 then result will be -1 + */ + + int val1[] = {1522, -100, 5, 0, -856, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + Datum val1_datum = Int32GetDatum(val1[i]); + Datum val2_datum = Int32GetDatum(val2[i]); + + char* testcase = psprintf("%d", i + 1); + + Datum expected; + Datum obtained; + char expected_str[MAX_TEST_MESSAGE_LENGTH]; + char obtained_str[MAX_TEST_MESSAGE_LENGTH]; + + if(val1[i] > val2[i]) + expected = 1; + else if(val1[i] < val2[i]) + expected = -1; + else + expected = 0; + + obtained = DirectFunctionCall2(int4_fixeddecimal_cmp, val1_datum, val2_datum); + snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%ld", expected); + snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%ld", obtained); + + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected_str, obtained_str , testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimalum(void) +{ + /* + * To establish the expected behavior of our code, it is crucial to test both positive and negative scenarios. + * So in this test, we expect an out of range error. + * When this error occurs as anticipated, the test is considered successful. + */ + + int64 arg1 = INT64_MIN; + ErrorData *errorData; + MemoryContext oldcontext; + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = false; + + oldcontext = CurrentMemoryContext; + PG_TRY(); + { + DirectFunctionCall1(fixeddecimalum, arg1); + } + PG_CATCH(); + { + MemoryContextSwitchTo(oldcontext); + errorData = CopyErrorData(); + FlushErrorState(); + snprintf(testResult->message, MAX_TEST_MESSAGE_LENGTH, "%s, %s", testResult->message, errorData->message); + testResult->result = true; + FreeErrorData(errorData); + } + PG_END_TRY(); + + // If the error doesn't occurr, then the following message gets displayed + if(testResult->result == false) + strncpy(testResult->message, ", Out of Range error doesn't occur", MAX_TEST_MESSAGE_LENGTH); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_ge(void) +{ + /* + * This function checks whether val1 is greater than or equal to val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] >= val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_le(void) +{ + /* + * This function checks whether val1 is less than or equal to val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] <= val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_le, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_gt(void) +{ + /* + * This function checks whether val1 is greater than val2 or not. + */ + + int val1[] = {152, -100, 5, 0, -85}; + int val2[] = {982, 200, 0, -24, -567}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] > val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_ne(void) +{ + /* + * This function checks whether val1 is not equal to val2 or not. + */ + + int val1[] = {5, 0, -85}; + int val2[] = {0, -24, -567}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + bool expected = (val1[i] != val2[i]); + Datum temp = DirectFunctionCall2(fixeddecimal_int2_ge, Int32GetDatum(val1[i]), Int32GetDatum(val2[i])); + bool obtained = DatumGetBool(temp); + + char* testcase = psprintf("%d", i + 1); + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected ? "True" : "False", obtained ? "True" : "False", testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +} + + +TestResult* +test_fixeddecimal_int2_cmp(void) +{ + /* + * This function compares val1 and val2. + * val1 > val2 then result will be 1 + * val1 == val2 then result will be 0 + * val1 < val2 then result will be -1 + */ + + int val1[] = {152, -100, 5, 0, -85, 0}; + int val2[] = {982, 200, 0, -24, -567, 0}; + + int numValues = sizeof(val1) / sizeof(val1[0]); + + TestResult* testResult = palloc0(sizeof(TestResult)); + testResult->result = true; + + for (int i = 0; i < numValues; i++) { + Datum val1_datum = Int32GetDatum(val1[i]); + Datum val2_datum = Int32GetDatum(val2[i]); + + char* testcase = psprintf("%d", i + 1); + + Datum expected; + Datum obtained; + char expected_str[MAX_TEST_MESSAGE_LENGTH]; + char obtained_str[MAX_TEST_MESSAGE_LENGTH]; + + if(val1[i] > val2[i]) + expected = 1; + else if(val1[i] < val2[i]) + expected = -1; + else + expected = 0; + + obtained = DirectFunctionCall2(fixeddecimal_int2_cmp, val1_datum, val2_datum); + snprintf(expected_str, MAX_TEST_MESSAGE_LENGTH, "%ld", expected); + snprintf(obtained_str, MAX_TEST_MESSAGE_LENGTH, "%ld", obtained); + + TEST_ASSERT_TESTCASE(expected == obtained, testcase, expected_str, obtained_str , testResult); + } + + TEST_ASSERT(expected == obtained, testResult); + + return testResult; +}