AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Prototype for the test wrapper provided in the module */7void test_jsonArrayLengthFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv);8 9static sqlite3 *gDb = NULL;10 11/* Helper: Initialize a sqlite3_context for direct function invocation */12static void initContext(sqlite3_context *pCtx){13 memset(pCtx, 0, sizeof(*pCtx));14 memset(&pCtx->s, 0, sizeof(pCtx->s));15 pCtx->pOut = &pCtx->s;16 pCtx->s.db = gDb;17}18 19/* Helper: Create a sqlite3_value containing a UTF-8 text string */20static sqlite3_value* makeTextValue(const char *z){21 Mem *v = sqlite3ValueNew(gDb);22 TEST_ASSERT_NOT_NULL(v);23 int rc = sqlite3VdbeMemSetStr(v, z, -1, SQLITE_UTF8, SQLITE_TRANSIENT);24 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);25 return (sqlite3_value*)v;26}27 28/* Helper: Create a sqlite3_value that is SQL NULL */29static sqlite3_value* makeNullValue(void){30 Mem *v = sqlite3ValueNew(gDb);31 TEST_ASSERT_NOT_NULL(v);32 sqlite3VdbeMemSetNull(v);33 return (sqlite3_value*)v;34}35 36/* Helper: Clean up a context's output Mem */37static void cleanupContext(sqlite3_context *pCtx){38 sqlite3VdbeMemRelease(&pCtx->s);39 memset(&pCtx->s, 0, sizeof(pCtx->s));40}41 42void setUp(void) {43 int rc = sqlite3_open(":memory:", &gDb);44 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);45}46 47void tearDown(void) {48 if( gDb ){49 sqlite3_close(gDb);50 gDb = NULL;51 }52}53 54/* Basic: array length of [1,2,3] => 3 */55void test_jsonArrayLengthFunc_basic_array(void){56 sqlite3_context ctx;57 initContext(&ctx);58 59 sqlite3_value *argv[1];60 argv[0] = makeTextValue("[1,2,3]");61 62 test_jsonArrayLengthFunc(&ctx, 1, argv);63 64 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));65 TEST_ASSERT_EQUAL_INT64(3, sqlite3_value_int64((sqlite3_value*)&ctx.s));66 TEST_ASSERT_EQUAL_INT(0, ctx.isError);67 68 sqlite3ValueFree((Mem*)argv[0]);69 cleanupContext(&ctx);70}71 72/* Empty array: [] => 0 */73void test_jsonArrayLengthFunc_empty_array(void){74 sqlite3_context ctx;75 initContext(&ctx);76 77 sqlite3_value *argv[1];78 argv[0] = makeTextValue("[]");79 80 test_jsonArrayLengthFunc(&ctx, 1, argv);81 82 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));83 TEST_ASSERT_EQUAL_INT64(0, sqlite3_value_int64((sqlite3_value*)&ctx.s));84 TEST_ASSERT_EQUAL_INT(0, ctx.isError);85 86 sqlite3ValueFree((Mem*)argv[0]);87 cleanupContext(&ctx);88}89 90/* Non-array inputs: object, number, null => 0 */91void test_jsonArrayLengthFunc_not_array_inputs(void){92 sqlite3_context ctx;93 sqlite3_value *argv[1];94 95 /* Object {} */96 initContext(&ctx);97 argv[0] = makeTextValue("{\"a\":1}");98 test_jsonArrayLengthFunc(&ctx, 1, argv);99 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));100 TEST_ASSERT_EQUAL_INT64(0, sqlite3_value_int64((sqlite3_value*)&ctx.s));101 TEST_ASSERT_EQUAL_INT(0, ctx.isError);102 sqlite3ValueFree((Mem*)argv[0]);103 cleanupContext(&ctx);104 105 /* Number */106 initContext(&ctx);107 argv[0] = makeTextValue("5");108 test_jsonArrayLengthFunc(&ctx, 1, argv);109 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));110 TEST_ASSERT_EQUAL_INT64(0, sqlite3_value_int64((sqlite3_value*)&ctx.s));111 TEST_ASSERT_EQUAL_INT(0, ctx.isError);112 sqlite3ValueFree((Mem*)argv[0]);113 cleanupContext(&ctx);114 115 /* null */116 initContext(&ctx);117 argv[0] = makeTextValue("null");118 test_jsonArrayLengthFunc(&ctx, 1, argv);119 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));120 TEST_ASSERT_EQUAL_INT64(0, sqlite3_value_int64((sqlite3_value*)&ctx.s));121 TEST_ASSERT_EQUAL_INT(0, ctx.isError);122 sqlite3ValueFree((Mem*)argv[0]);123 cleanupContext(&ctx);124}125 126/* PATH exists and points to arrays */127void test_jsonArrayLengthFunc_path_to_array(void){128 sqlite3_context ctx;129 initContext(&ctx);130 131 sqlite3_value *argv[2];132 argv[0] = makeTextValue("{\"a\":[1,2,3],\"b\":[4,5],\"c\":0}");133 argv[1] = makeTextValue("$.a");134 135 test_jsonArrayLengthFunc(&ctx, 2, argv);136 137 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));138 TEST_ASSERT_EQUAL_INT64(3, sqlite3_value_int64((sqlite3_value*)&ctx.s));139 TEST_ASSERT_EQUAL_INT(0, ctx.isError);140 141 sqlite3ValueFree((Mem*)argv[0]);142 sqlite3ValueFree((Mem*)argv[1]);143 cleanupContext(&ctx);144 145 /* Another path in same doc */146 initContext(&ctx);147 argv[0] = makeTextValue("{\"a\":[1,2,3],\"b\":[4,5],\"c\":0}");148 argv[1] = makeTextValue("$.b");149 150 test_jsonArrayLengthFunc(&ctx, 2, argv);151 152 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));153 TEST_ASSERT_EQUAL_INT64(2, sqlite3_value_int64((sqlite3_value*)&ctx.s));154 TEST_ASSERT_EQUAL_INT(0, ctx.isError);155 156 sqlite3ValueFree((Mem*)argv[0]);157 sqlite3ValueFree((Mem*)argv[1]);158 cleanupContext(&ctx);159}160 161/* PATH exists but is not an array => 0 */162void test_jsonArrayLengthFunc_path_to_nonarray(void){163 sqlite3_context ctx;164 initContext(&ctx);165 166 sqlite3_value *argv[2];167 argv[0] = makeTextValue("{\"a\": 5, \"b\": [1]}");168 argv[1] = makeTextValue("$.a");169 170 test_jsonArrayLengthFunc(&ctx, 2, argv);171 172 TEST_ASSERT_EQUAL_INT(SQLITE_INTEGER, sqlite3_value_type((sqlite3_value*)&ctx.s));173 TEST_ASSERT_EQUAL_INT64(0, sqlite3_value_int64((sqlite3_value*)&ctx.s));174 TEST_ASSERT_EQUAL_INT(0, ctx.isError);175 176 sqlite3ValueFree((Mem*)argv[0]);177 sqlite3ValueFree((Mem*)argv[1]);178 cleanupContext(&ctx);179}180 181/* PATH does not exist => result is NULL and no error */182void test_jsonArrayLengthFunc_path_not_found_returns_null(void){183 sqlite3_context ctx;184 initContext(&ctx);185 186 sqlite3_value *argv[2];187 argv[0] = makeTextValue("{\"a\":[1]}");188 argv[1] = makeTextValue("$.x");189 190 test_jsonArrayLengthFunc(&ctx, 2, argv);191 192 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&ctx.s));193 TEST_ASSERT_EQUAL_INT(0, ctx.isError);194 195 sqlite3ValueFree((Mem*)argv[0]);196 sqlite3ValueFree((Mem*)argv[1]);197 cleanupContext(&ctx);198}199 200/* PATH is malformed => error flagged on context */201void test_jsonArrayLengthFunc_path_malformed_sets_error(void){202 sqlite3_context ctx;203 initContext(&ctx);204 205 sqlite3_value *argv[2];206 argv[0] = makeTextValue("{\"a\":[1,2,3]}");207 argv[1] = makeTextValue("$.");208 209 test_jsonArrayLengthFunc(&ctx, 2, argv);210 211 TEST_ASSERT_NOT_EQUAL(0, ctx.isError);212 /* Result value is not overwritten when error; commonly NULL */213 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&ctx.s));214 215 sqlite3ValueFree((Mem*)argv[0]);216 sqlite3ValueFree((Mem*)argv[1]);217 cleanupContext(&ctx);218}219 220/* PATH argument is SQL NULL => result is NULL and no error */221void test_jsonArrayLengthFunc_path_argument_null(void){222 sqlite3_context ctx;223 initContext(&ctx);224 225 sqlite3_value *argv[2];226 argv[0] = makeTextValue("{\"a\":[1,2]}");227 argv[1] = makeNullValue();228 229 test_jsonArrayLengthFunc(&ctx, 2, argv);230 231 TEST_ASSERT_EQUAL_INT(SQLITE_NULL, sqlite3_value_type((sqlite3_value*)&ctx.s));232 TEST_ASSERT_EQUAL_INT(0, ctx.isError);233 234 sqlite3ValueFree((Mem*)argv[0]);235 sqlite3ValueFree((Mem*)argv[1]);236 cleanupContext(&ctx);237}238 239int main(void) {240 UNITY_BEGIN();241 RUN_TEST(test_jsonArrayLengthFunc_basic_array);242 RUN_TEST(test_jsonArrayLengthFunc_empty_array);243 RUN_TEST(test_jsonArrayLengthFunc_not_array_inputs);244 RUN_TEST(test_jsonArrayLengthFunc_path_to_array);245 RUN_TEST(test_jsonArrayLengthFunc_path_to_nonarray);246 RUN_TEST(test_jsonArrayLengthFunc_path_not_found_returns_null);247 RUN_TEST(test_jsonArrayLengthFunc_path_malformed_sets_error);248 RUN_TEST(test_jsonArrayLengthFunc_path_argument_null);249 return UNITY_END();250}