Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreeCloseCursor.c172 linesDownload Raw Back to tests
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}