Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_btreeCursorWithLock.c186 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* Prototype for the wrapper of the static function under test */6int test_btreeCursorWithLock(7  Btree *p, Pgno iTable, int wrFlag, struct KeyInfo *pKeyInfo, BtCursor *pCur8);9 10static sqlite3 *gDb = NULL;11static Btree *gBtree = NULL;12 13static BtCursor* alloc_zeroed_cursor(void){14  int n = sqlite3BtreeCursorSize();15  BtCursor *pCur = (BtCursor*)sqlite3_malloc(n);16  TEST_ASSERT_NOT_NULL_MESSAGE(pCur, "Failed to allocate BtCursor");17  memset(pCur, 0, n);18  sqlite3BtreeCursorZero(pCur);19  return pCur;20}21 22static void free_and_close_cursor(BtCursor *pCur){23  if( pCur ){24    if( pCur->pBtree ){25      /* Only close if it was successfully opened */26      sqlite3BtreeCloseCursor(pCur);27    }28    sqlite3_free(pCur);29  }30}31 32static void begin_read_txn(Btree *p){33  sqlite3_mutex_enter(gDb->mutex);34  int rc = sqlite3BtreeBeginTrans(p, 0, NULL);35  sqlite3_mutex_leave(gDb->mutex);36  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);37}38 39static void begin_write_txn(Btree *p){40  sqlite3_mutex_enter(gDb->mutex);41  int rc = sqlite3BtreeBeginTrans(p, 1, NULL);42  sqlite3_mutex_leave(gDb->mutex);43  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);44}45 46static Pgno create_table(Btree *p){47  Pgno iTable = 0;48  sqlite3_mutex_enter(gDb->mutex);49  begin_write_txn(p);50  int rc = sqlite3BtreeCreateTable(p, &iTable, BTREE_INTKEY|BTREE_LEAFDATA);51  sqlite3_mutex_leave(gDb->mutex);52  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);53  TEST_ASSERT_TRUE_MESSAGE(iTable>=2, "Expected a valid root page number >=2");54  return iTable;55}56 57void setUp(void) {58  int rc = sqlite3_open(":memory:", &gDb);59  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);60  /* Get the main database btree */61  gBtree = gDb->aDb[0].pBt;62  TEST_ASSERT_NOT_NULL_MESSAGE(gBtree, "Main Btree should be available");63}64 65void tearDown(void) {66  if( gDb ){67    sqlite3_close(gDb);68    gDb = NULL;69    gBtree = NULL;70  }71}72 73/* Test creating a read-only cursor on a new table */74void test_btreeCursorWithLock_read_cursor_ok(void){75  Pgno root = create_table(gBtree);76  BtCursor *c1 = alloc_zeroed_cursor();77 78  begin_write_txn(gBtree); /* Having a write txn still satisfies read txn requirement */79  sqlite3_mutex_enter(gDb->mutex);80  int rc = test_btreeCursorWithLock(gBtree, root, 0, NULL, c1);81  sqlite3_mutex_leave(gDb->mutex);82 83  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);84  TEST_ASSERT_EQUAL_UINT32(root, c1->pgnoRoot);85  TEST_ASSERT_EQUAL_INT(0, (c1->curFlags & BTCF_WriteFlag)!=0);86  TEST_ASSERT_EQUAL_INT(PAGER_GET_READONLY, c1->curPagerFlags);87 88  free_and_close_cursor(c1);89}90 91/* Test creating a write cursor on a new table */92void test_btreeCursorWithLock_write_cursor_ok_and_tmpSpace(void){93  Pgno root = create_table(gBtree);94  BtCursor *c2 = alloc_zeroed_cursor();95 96  begin_write_txn(gBtree);97  sqlite3_mutex_enter(gDb->mutex);98  int rc = test_btreeCursorWithLock(gBtree, root, BTREE_WRCSR, NULL, c2);99  sqlite3_mutex_leave(gDb->mutex);100 101  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);102  TEST_ASSERT_TRUE_MESSAGE((c2->curFlags & BTCF_WriteFlag)!=0, "Write flag not set on cursor");103  TEST_ASSERT_NOT_NULL_MESSAGE(gBtree->pBt->pTmpSpace, "pTmpSpace should be allocated for write cursor");104 105  free_and_close_cursor(c2);106}107 108/* Test multiple cursors on the same table set BTCF_Multiple flag on both */109void test_btreeCursorWithLock_multiple_cursors_flag_set(void){110  Pgno root = create_table(gBtree);111 112  BtCursor *c1 = alloc_zeroed_cursor();113  BtCursor *c2 = alloc_zeroed_cursor();114 115  begin_write_txn(gBtree);116 117  sqlite3_mutex_enter(gDb->mutex);118  int rc1 = test_btreeCursorWithLock(gBtree, root, 0, NULL, c1);119  sqlite3_mutex_leave(gDb->mutex);120  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc1);121  /* First cursor alone might not have BTCF_Multiple yet */122 123  sqlite3_mutex_enter(gDb->mutex);124  int rc2 = test_btreeCursorWithLock(gBtree, root, 0, NULL, c2);125  sqlite3_mutex_leave(gDb->mutex);126  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc2);127 128  /* Now both should have BTCF_Multiple */129  TEST_ASSERT_TRUE_MESSAGE((c1->curFlags & BTCF_Multiple)!=0, "First cursor missing BTCF_Multiple");130  TEST_ASSERT_TRUE_MESSAGE((c2->curFlags & BTCF_Multiple)!=0, "Second cursor missing BTCF_Multiple");131 132  free_and_close_cursor(c2);133  free_and_close_cursor(c1);134}135 136/* Test invalid iTable less than 1 returns error and does not modify cursor */137void test_btreeCursorWithLock_invalid_root_page_error(void){138  BtCursor *c = alloc_zeroed_cursor();139 140  begin_read_txn(gBtree);141  sqlite3_mutex_enter(gDb->mutex);142  int rc = test_btreeCursorWithLock(gBtree, 0, 0, NULL, c);143  sqlite3_mutex_leave(gDb->mutex);144 145  TEST_ASSERT_NOT_EQUAL_INT(SQLITE_OK, rc);146  TEST_ASSERT_NULL_MESSAGE(c->pBtree, "Cursor should not be initialized on failure");147  TEST_ASSERT_NULL_MESSAGE(c->pBt, "Cursor should not be initialized on failure");148  free_and_close_cursor(c);149}150 151/* Test empty database with iTable=1 and read-only cursor */152void test_btreeCursorWithLock_empty_db_root1_read_ok_pgnoRoot_zero(void){153  /* Open a fresh connection to ensure empty database state */154  sqlite3 *db2 = NULL;155  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db2));156  Btree *bt2 = db2->aDb[0].pBt;157  TEST_ASSERT_NOT_NULL(bt2);158 159  BtCursor *c = alloc_zeroed_cursor();160 161  /* Begin read transaction to initialize pPage1 and keep nPage==0 */162  sqlite3_mutex_enter(db2->mutex);163  int rcBegin = sqlite3BtreeBeginTrans(bt2, 0, NULL);164  sqlite3_mutex_leave(db2->mutex);165  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rcBegin);166 167  sqlite3_mutex_enter(db2->mutex);168  int rc = test_btreeCursorWithLock(bt2, 1, 0, NULL, c);169  sqlite3_mutex_leave(db2->mutex);170 171  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);172  TEST_ASSERT_EQUAL_UINT32(0u, c->pgnoRoot); /* Expect 0 due to empty db special-case */173 174  free_and_close_cursor(c);175  sqlite3_close(db2);176}177 178int main(void) {179  UNITY_BEGIN();180  RUN_TEST(test_btreeCursorWithLock_read_cursor_ok);181  RUN_TEST(test_btreeCursorWithLock_write_cursor_ok_and_tmpSpace);182  RUN_TEST(test_btreeCursorWithLock_multiple_cursors_flag_set);183  RUN_TEST(test_btreeCursorWithLock_invalid_root_page_error);184  RUN_TEST(test_btreeCursorWithLock_empty_db_root1_read_ok_pgnoRoot_zero);185  return UNITY_END();186}