AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6static sqlite3 *gDb = NULL;7 8static void open_memory_db(sqlite3 **ppDb){9 int rc = sqlite3_open(":memory:", ppDb);10 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);11 TEST_ASSERT_NOT_NULL(*ppDb);12}13static void close_db(sqlite3 *db){14 if( db ){15 sqlite3_close(db);16 }17}18 19void setUp(void) {20 /* Open a fresh in-memory database per test unless the test opens its own */21 if( gDb==NULL ){22 open_memory_db(&gDb);23 }24}25void tearDown(void) {26 if( gDb ){27 close_db(gDb);28 gDb = NULL;29 }30}31 32/* Helper: verify that a given BtCursor* is not in the BtShared cursor list */33static int cursor_in_list(BtShared *pBt, BtCursor *pC){34 BtCursor *pIter = pBt->pCursor;35 while( pIter ){36 if( pIter==pC ) return 1;37 pIter = pIter->pNext;38 }39 return 0;40}41 42void test_sqlite3BtreeCloseCursor_null_pointer_btree(void){43 /* Closing a cursor with pBtree==NULL should return SQLITE_OK and do nothing */44 BtCursor cur;45 memset(&cur, 0, sizeof(cur));46 int rc = sqlite3BtreeCloseCursor(&cur);47 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);48 TEST_ASSERT_NULL(cur.pBtree);49}50 51void test_sqlite3BtreeCloseCursor_single_cursor_unlinks_and_clears(void){52 /* Use main database btree */53 sqlite3 *db = gDb;54 Btree *p = db->aDb[0].pBt;55 TEST_ASSERT_NOT_NULL(p);56 57 sqlite3_mutex_enter(db->mutex);58 59 /* Begin a read transaction so opening a cursor is allowed */60 int rc = sqlite3BtreeBeginTrans(p, 0, 0);61 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);62 63 /* Open a read-only cursor on root table (sqlite_schema has root 1) */64 BtCursor c;65 sqlite3BtreeCursorZero(&c);66 rc = sqlite3BtreeCursor(p, 1, 0, NULL, &c);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);68 69 /* Ensure it linked into BtShared cursor list */70 TEST_ASSERT_TRUE(cursor_in_list(p->pBt, &c));71 72 /* Optionally position the cursor to ensure pages are loaded */73 int isEmpty = 0;74 rc = sqlite3BtreeFirst(&c, &isEmpty);75 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);76 77 /* Close the cursor */78 rc = sqlite3BtreeCloseCursor(&c);79 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);80 81 /* Validate postconditions */82 TEST_ASSERT_NULL(c.pBtree);83 TEST_ASSERT_EQUAL_INT(-1, c.iPage);84 TEST_ASSERT_FALSE(cursor_in_list(p->pBt, &c));85 86 sqlite3_mutex_leave(db->mutex);87}88 89void test_sqlite3BtreeCloseCursor_two_cursors_head_and_tail_remove(void){90 sqlite3 *db = gDb;91 Btree *p = db->aDb[0].pBt;92 TEST_ASSERT_NOT_NULL(p);93 94 sqlite3_mutex_enter(db->mutex);95 96 int rc = sqlite3BtreeBeginTrans(p, 0, 0);97 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);98 99 BtCursor c1, c2;100 sqlite3BtreeCursorZero(&c1);101 sqlite3BtreeCursorZero(&c2);102 103 rc = sqlite3BtreeCursor(p, 1, 0, NULL, &c1);104 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);105 rc = sqlite3BtreeCursor(p, 1, 0, NULL, &c2);106 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);107 108 /* Newest cursor should be at the head of the list */109 TEST_ASSERT_EQUAL_PTR(&c2, p->pBt->pCursor);110 TEST_ASSERT_EQUAL_PTR(&c1, c2.pNext);111 112 /* Close head (c2), leaving c1 as head */113 rc = sqlite3BtreeCloseCursor(&c2);114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);115 TEST_ASSERT_EQUAL_PTR(&c1, p->pBt->pCursor);116 TEST_ASSERT_FALSE(cursor_in_list(p->pBt, &c2));117 TEST_ASSERT_NULL(c2.pBtree);118 119 /* Close remaining (c1), list becomes empty */120 rc = sqlite3BtreeCloseCursor(&c1);121 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);122 TEST_ASSERT_NULL(p->pBt->pCursor);123 TEST_ASSERT_FALSE(cursor_in_list(p->pBt, &c1));124 TEST_ASSERT_NULL(c1.pBtree);125 126 sqlite3_mutex_leave(db->mutex);127}128 129void test_sqlite3BtreeCloseCursor_BTREE_SINGLE_auto_closes_btree(void){130 sqlite3 *db = gDb;131 sqlite3_vfs *pVfs = sqlite3_vfs_find(0);132 TEST_ASSERT_NOT_NULL(pVfs);133 134 sqlite3_mutex_enter(db->mutex);135 136 Btree *pSingle = NULL;137 /* Open an ephemeral single-use btree */138 int rc = sqlite3BtreeOpen(pVfs, NULL, db, &pSingle,139 BTREE_SINGLE | BTREE_OMIT_JOURNAL | BTREE_MEMORY,140 SQLITE_OPEN_MEMORY | SQLITE_OPEN_TEMP_DB);141 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);142 TEST_ASSERT_NOT_NULL(pSingle);143 144 /* Start a read transaction so cursor open is allowed */145 rc = sqlite3BtreeBeginTrans(pSingle, 0, 0);146 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);147 148 BtCursor c;149 sqlite3BtreeCursorZero(&c);150 /* Open a cursor. If the database is empty, iTable=1 may resolve to 0,151 but opening still succeeds and links into the list. */152 rc = sqlite3BtreeCursor(pSingle, 1, 0, NULL, &c);153 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);154 TEST_ASSERT_NOT_NULL(c.pBtree);155 156 /* Close the only cursor. For BTREE_SINGLE, this should auto-close the Btree. */157 rc = sqlite3BtreeCloseCursor(&c);158 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);159 TEST_ASSERT_NULL(c.pBtree);160 161 /* Do not touch pSingle after this; it may have been freed. */162 sqlite3_mutex_leave(db->mutex);163}164 165int main(void) {166 UNITY_BEGIN();167 RUN_TEST(test_sqlite3BtreeCloseCursor_null_pointer_btree);168 RUN_TEST(test_sqlite3BtreeCloseCursor_single_cursor_unlinks_and_clears);169 RUN_TEST(test_sqlite3BtreeCloseCursor_two_cursors_head_and_tail_remove);170 RUN_TEST(test_sqlite3BtreeCloseCursor_BTREE_SINGLE_auto_closes_btree);171 return UNITY_END();172}