AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3 4#include <stdio.h>5#include <string.h>6 7extern int test_jsonEachNext(sqlite3_vtab_cursor *cur);8 9/* Helper: find the first virtual-table cursor in a prepared statement */10static sqlite3_vtab_cursor* findVtabCursor(sqlite3_stmt *pStmt){11 Vdbe *pV = (Vdbe*)pStmt;12 if( pV==NULL ) return NULL;13 for(int i=0; i<pV->nCursor; i++){14 VdbeCursor *pC = pV->apCsr[i];15 if( pC && pC->pVtabCursor ){16 return pC->pVtabCursor;17 }18 }19 return NULL;20}21 22void setUp(void) {23 /* Setup code here, or leave empty */24}25 26void tearDown(void) {27 /* Cleanup code here, or leave empty */28}29 30/* Test 1: Non-recursive array iteration skips exactly one element */31void test_jsonEachNext_array_nonrecursive_skips_one(void){32 sqlite3 *db = NULL;33 sqlite3_stmt *pStmt = NULL;34 int rc;35 36 rc = sqlite3_open(":memory:", &db);37 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);38 39 const char *zSql = "SELECT value FROM json_each('[1,2,3]')";40 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);41 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);42 43 /* First row: expect "1" */44 rc = sqlite3_step(pStmt);45 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);46 const unsigned char *zVal = sqlite3_column_text(pStmt, 0);47 TEST_ASSERT_NOT_NULL(zVal);48 TEST_ASSERT_EQUAL_STRING("1", (const char*)zVal);49 50 /* Grab vtab cursor and advance it manually once */51 sqlite3_vtab_cursor *pCur = findVtabCursor(pStmt);52 TEST_ASSERT_NOT_NULL(pCur);53 rc = test_jsonEachNext(pCur);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55 56 /* Next step should now yield "3" (since "2" was skipped) */57 rc = sqlite3_step(pStmt);58 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);59 zVal = sqlite3_column_text(pStmt, 0);60 TEST_ASSERT_NOT_NULL(zVal);61 TEST_ASSERT_EQUAL_STRING("3", (const char*)zVal);62 63 /* No more rows */64 rc = sqlite3_step(pStmt);65 TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);66 67 sqlite3_finalize(pStmt);68 sqlite3_close(db);69}70 71/* Test 2: Non-recursive object iteration; manual next causes DONE */72void test_jsonEachNext_object_nonrecursive_skips_to_done(void){73 sqlite3 *db = NULL;74 sqlite3_stmt *pStmt = NULL;75 int rc;76 77 rc = sqlite3_open(":memory:", &db);78 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);79 80 const char *zSql = "SELECT key FROM json_each('{\"a\":1,\"b\":2}')";81 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);82 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);83 84 /* First row: expect key "a" */85 rc = sqlite3_step(pStmt);86 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);87 const unsigned char *zKey = sqlite3_column_text(pStmt, 0);88 TEST_ASSERT_NOT_NULL(zKey);89 TEST_ASSERT_EQUAL_STRING("a", (const char*)zKey);90 91 /* Manually advance once; this should skip the remaining row */92 sqlite3_vtab_cursor *pCur = findVtabCursor(pStmt);93 TEST_ASSERT_NOT_NULL(pCur);94 rc = test_jsonEachNext(pCur);95 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);96 97 /* Next step should be DONE (since "b" was skipped) */98 rc = sqlite3_step(pStmt);99 TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc);100 101 sqlite3_finalize(pStmt);102 sqlite3_close(db);103}104 105/* Test 3: Recursive json_tree; ensure depth-first traversal path update */106void test_jsonEachNext_recursive_json_tree_array_path(void){107 sqlite3 *db = NULL;108 sqlite3_stmt *pStmt = NULL;109 int rc;110 111 rc = sqlite3_open(":memory:", &db);112 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);113 114 /* [1, [2,3]] traversal should be: "$", "$[0]", "$[1]", "$[1][0]", "$[1][1]" */115 const char *zSql = "SELECT path FROM json_tree('[1,[2,3]]')";116 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);117 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);118 119 /* First row: root "$" */120 rc = sqlite3_step(pStmt);121 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);122 const unsigned char *zPath = sqlite3_column_text(pStmt, 0);123 TEST_ASSERT_NOT_NULL(zPath);124 TEST_ASSERT_EQUAL_STRING("$", (const char*)zPath);125 126 /* Manually advance once: moves to "$[0]" */127 sqlite3_vtab_cursor *pCur = findVtabCursor(pStmt);128 TEST_ASSERT_NOT_NULL(pCur);129 rc = test_jsonEachNext(pCur);130 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);131 132 /* Next sqlite3_step will advance again, returning "$[1]" */133 rc = sqlite3_step(pStmt);134 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);135 zPath = sqlite3_column_text(pStmt, 0);136 TEST_ASSERT_NOT_NULL(zPath);137 TEST_ASSERT_EQUAL_STRING("$[1]", (const char*)zPath);138 139 sqlite3_finalize(pStmt);140 sqlite3_close(db);141}142 143/* Test 4: Recursive nested arrays; ensure path becomes "$[0][0]" after manual skip+step */144void test_jsonEachNext_recursive_nested_arrays_path(void){145 sqlite3 *db = NULL;146 sqlite3_stmt *pStmt = NULL;147 int rc;148 149 rc = sqlite3_open(":memory:", &db);150 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);151 152 /* [[1,2]] traversal: "$", "$[0]", "$[0][0]", "$[0][1]" */153 const char *zSql = "SELECT path FROM json_tree('[[1,2]]')";154 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);155 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);156 157 /* First row: root "$" */158 rc = sqlite3_step(pStmt);159 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);160 const unsigned char *zPath = sqlite3_column_text(pStmt, 0);161 TEST_ASSERT_NOT_NULL(zPath);162 TEST_ASSERT_EQUAL_STRING("$", (const char*)zPath);163 164 /* Manually advance once: to "$[0]" */165 sqlite3_vtab_cursor *pCur = findVtabCursor(pStmt);166 TEST_ASSERT_NOT_NULL(pCur);167 rc = test_jsonEachNext(pCur);168 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);169 170 /* Next step advances to "$[0][0]" */171 rc = sqlite3_step(pStmt);172 TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);173 zPath = sqlite3_column_text(pStmt, 0);174 TEST_ASSERT_NOT_NULL(zPath);175 TEST_ASSERT_EQUAL_STRING("$[0][0]", (const char*)zPath);176 177 sqlite3_finalize(pStmt);178 sqlite3_close(db);179}180 181int main(void) {182 UNITY_BEGIN();183 RUN_TEST(test_jsonEachNext_array_nonrecursive_skips_one);184 RUN_TEST(test_jsonEachNext_object_nonrecursive_skips_to_done);185 RUN_TEST(test_jsonEachNext_recursive_json_tree_array_path);186 RUN_TEST(test_jsonEachNext_recursive_nested_arrays_path);187 return UNITY_END();188}