AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Unity fixtures */7void setUp(void) {8 /* no-op */9}10void tearDown(void) {11 /* no-op */12}13 14/* Helper: open an in-memory DB and enter its mutex (if present) */15static sqlite3* open_db_and_lock(void){16 sqlite3 *db = 0;17 int rc = sqlite3_open(":memory:", &db);18 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);19 if( db && db->mutex ){20 sqlite3_mutex_enter(db->mutex);21 }22 return db;23}24 25/* Helper: leave db mutex (if held) and close DB */26static void close_db_and_unlock(sqlite3 *db){27 if( !db ) return;28 if( db->mutex ){29 sqlite3_mutex_leave(db->mutex);30 }31 sqlite3_close(db);32}33 34/* Helper: allocate and initialize a fabricated Btree + BtShared.35 sharable!=0 => p->sharable is true; otherwise false.36*/37static Btree* make_btree(sqlite3 *db, int sharable){38 Btree *p = (Btree*)sqlite3_malloc(sizeof(Btree));39 TEST_ASSERT_NOT_NULL(p);40 memset(p, 0, sizeof(Btree));41 p->db = db;42 p->sharable = sharable ? 1 : 0;43 p->pBt = (BtShared*)sqlite3_malloc(sizeof(BtShared));44 TEST_ASSERT_NOT_NULL(p->pBt);45 memset(p->pBt, 0, sizeof(BtShared));46 /* Allocate a mutex for BtShared. In single-thread builds this may be NULL,47 which is fine since we don't depend on it there. */48 p->pBt->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);49 /* For non-sharable btrees, BtShared.db should already match p->db50 to satisfy preconditions in the threadsafe implementation. */51 if( !p->sharable ){52 p->pBt->db = db;53 }54 return p;55}56 57/* Helper: free fabricated Btree + BtShared; ensure unlocked first */58static void free_btree(Btree *p){59 if( !p ) return;60#if SQLITE_THREADSAFE61 if( p->sharable && p->locked ){62 /* Leave until fully unlocked */63 while( p->wantToLock > 0 ){64 sqlite3BtreeLeave(p);65 }66 }67#endif68 if( p->pBt ){69 if( p->pBt->mutex ){70 sqlite3_mutex_free(p->pBt->mutex);71 }72 sqlite3_free(p->pBt);73 }74 sqlite3_free(p);75}76 77/* Test: sharable Btree basic enter acquires lock, sets db, and updates counters */78void test_sqlite3BtreeEnter_sharable_basic(void){79 sqlite3 *db = open_db_and_lock();80 Btree *p = make_btree(db, 1);81 82 /* Preconditions */83 TEST_ASSERT_EQUAL_INT(0, p->wantToLock);84 TEST_ASSERT_EQUAL_INT(0, p->locked);85 86 sqlite3BtreeEnter(p);87 88#if SQLITE_THREADSAFE89 TEST_ASSERT_EQUAL_INT(1, p->wantToLock);90 TEST_ASSERT_EQUAL_INT(1, p->locked);91 TEST_ASSERT_EQUAL_PTR(db, p->pBt->db);92 if( p->pBt->mutex ){93 TEST_ASSERT_TRUE(sqlite3_mutex_held(p->pBt->mutex));94 }95 /* Clean up: leave once to drop the lock */96 sqlite3BtreeLeave(p);97 TEST_ASSERT_EQUAL_INT(0, p->wantToLock);98 TEST_ASSERT_EQUAL_INT(0, p->locked);99#else100 /* Non-threadsafe: only pBt->db is set/maintained */101 TEST_ASSERT_EQUAL_PTR(db, p->pBt->db);102 TEST_ASSERT_EQUAL_INT(0, p->wantToLock);103 TEST_ASSERT_EQUAL_INT(0, p->locked);104#endif105 106 free_btree(p);107 close_db_and_unlock(db);108}109 110/* Test: recursive enter increments wantToLock but does not re-lock */111void test_sqlite3BtreeEnter_recursive(void){112 sqlite3 *db = open_db_and_lock();113 Btree *p = make_btree(db, 1);114 115 sqlite3BtreeEnter(p);116 sqlite3BtreeEnter(p);117 118#if SQLITE_THREADSAFE119 TEST_ASSERT_EQUAL_INT(2, p->wantToLock);120 TEST_ASSERT_EQUAL_INT(1, p->locked);121 if( p->pBt->mutex ){122 TEST_ASSERT_TRUE(sqlite3_mutex_held(p->pBt->mutex));123 }124 /* Leave twice to unwind recursion */125 sqlite3BtreeLeave(p);126 TEST_ASSERT_EQUAL_INT(1, p->wantToLock);127 TEST_ASSERT_EQUAL_INT(1, p->locked);128 sqlite3BtreeLeave(p);129 TEST_ASSERT_EQUAL_INT(0, p->wantToLock);130 TEST_ASSERT_EQUAL_INT(0, p->locked);131#else132 /* In non-threadsafe builds, sqlite3BtreeEnter only sets pBt->db */133 TEST_ASSERT_EQUAL_PTR(db, p->pBt->db);134#endif135 136 free_btree(p);137 close_db_and_unlock(db);138}139 140/* Test: non-sharable Btree -> enter is a no-op for locking/counters */141void test_sqlite3BtreeEnter_unsharable_noop(void){142 sqlite3 *db = open_db_and_lock();143 Btree *p = make_btree(db, 0);144 145 sqlite3BtreeEnter(p);146 147#if SQLITE_THREADSAFE148 TEST_ASSERT_EQUAL_INT(0, p->wantToLock);149 TEST_ASSERT_EQUAL_INT(0, p->locked);150#endif151 TEST_ASSERT_EQUAL_PTR(db, p->pBt->db);152 153 free_btree(p);154 close_db_and_unlock(db);155}156 157int main(void){158 UNITY_BEGIN();159 RUN_TEST(test_sqlite3BtreeEnter_sharable_basic);160 RUN_TEST(test_sqlite3BtreeEnter_recursive);161 RUN_TEST(test_sqlite3BtreeEnter_unsharable_noop);162 return UNITY_END();163}