AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Wrapper for the static function provided by the build under test */7extern void test_lockTable(Parse *pParse, int iDb, Pgno iTab, u8 isWriteLock, const char *zName);8 9static sqlite3 *gDb = NULL;10 11void setUp(void) {12 int rc = sqlite3_open(":memory:", &gDb);13 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);14 TEST_ASSERT_NOT_NULL(gDb);15}16 17void tearDown(void) {18 if( gDb ){19 sqlite3_close(gDb);20 gDb = NULL;21 }22}23 24/* Helper to initialize a Parse object */25static void initParse(Parse *p){26 memset(p, 0, sizeof(*p));27 p->db = gDb;28}29 30/* Test 1: Basic add of a read lock and verify fields */31void test_lockTable_basic_add_read_lock(void){32 Parse p;33 initParse(&p);34 35 test_lockTable(&p, /*iDb*/0, /*iTab*/(Pgno)123, /*isWrite*/0, /*zName*/"t1");36 37 TEST_ASSERT_EQUAL_INT(1, p.nTableLock);38 TEST_ASSERT_NOT_NULL(p.aTableLock);39 40 TableLock *t = &p.aTableLock[0];41 TEST_ASSERT_EQUAL_INT(0, t->iDb);42 TEST_ASSERT_EQUAL_INT(123, (int)t->iTab);43 TEST_ASSERT_EQUAL_INT(0, (int)t->isWriteLock);44 TEST_ASSERT_EQUAL_PTR("t1", t->zLockName);45 46 sqlite3DbFree(gDb, p.aTableLock);47}48 49/* Test 2: Duplicate requests do not append, and write lock upgrades existing entry */50void test_lockTable_duplicate_does_not_add_but_upgrades_write(void){51 Parse p;52 initParse(&p);53 54 test_lockTable(&p, 1, (Pgno)200, 0, "tab");55 TEST_ASSERT_EQUAL_INT(1, p.nTableLock);56 TEST_ASSERT_EQUAL_INT(0, (int)p.aTableLock[0].isWriteLock);57 58 /* Duplicate read should not add a new entry and keep write flag at 0 */59 test_lockTable(&p, 1, (Pgno)200, 0, "tab");60 TEST_ASSERT_EQUAL_INT(1, p.nTableLock);61 TEST_ASSERT_EQUAL_INT(0, (int)p.aTableLock[0].isWriteLock);62 63 /* Duplicate with write=true should upgrade existing entry */64 test_lockTable(&p, 1, (Pgno)200, 1, "tab");65 TEST_ASSERT_EQUAL_INT(1, p.nTableLock);66 TEST_ASSERT_EQUAL_INT(1, (int)p.aTableLock[0].isWriteLock);67 68 /* Further duplicates should keep it at write lock */69 test_lockTable(&p, 1, (Pgno)200, 0, "tab");70 TEST_ASSERT_EQUAL_INT(1, p.nTableLock);71 TEST_ASSERT_EQUAL_INT(1, (int)p.aTableLock[0].isWriteLock);72 73 sqlite3DbFree(gDb, p.aTableLock);74}75 76/* Test 3: Multiple distinct locks are appended, verify ordering and fields */77void test_lockTable_multiple_distinct_entries(void){78 Parse p;79 initParse(&p);80 81 test_lockTable(&p, 0, (Pgno)10, 0, "a");82 test_lockTable(&p, 0, (Pgno)11, 1, "b");83 test_lockTable(&p, 2, (Pgno)99, 0, "c");84 85 TEST_ASSERT_EQUAL_INT(3, p.nTableLock);86 TEST_ASSERT_NOT_NULL(p.aTableLock);87 88 TableLock *t = p.aTableLock;89 90 /* Entry 0 */91 TEST_ASSERT_EQUAL_INT(0, t[0].iDb);92 TEST_ASSERT_EQUAL_INT(10, (int)t[0].iTab);93 TEST_ASSERT_EQUAL_INT(0, (int)t[0].isWriteLock);94 TEST_ASSERT_EQUAL_PTR("a", t[0].zLockName);95 96 /* Entry 1 */97 TEST_ASSERT_EQUAL_INT(0, t[1].iDb);98 TEST_ASSERT_EQUAL_INT(11, (int)t[1].iTab);99 TEST_ASSERT_EQUAL_INT(1, (int)t[1].isWriteLock);100 TEST_ASSERT_EQUAL_PTR("b", t[1].zLockName);101 102 /* Entry 2 */103 TEST_ASSERT_EQUAL_INT(2, t[2].iDb);104 TEST_ASSERT_EQUAL_INT(99, (int)t[2].iTab);105 TEST_ASSERT_EQUAL_INT(0, (int)t[2].isWriteLock);106 TEST_ASSERT_EQUAL_PTR("c", t[2].zLockName);107 108 sqlite3DbFree(gDb, p.aTableLock);109}110 111/* Test 4: Locks from a child Parse go to top-level Parse (sqlite3ParseToplevel behavior) */112void test_lockTable_uses_toplevel_from_child(void){113 Parse top, child;114 initParse(&top);115 initParse(&child);116 117 /* Make child reference top-level parse */118 child.pToplevel = ⊤119 120 test_lockTable(&child, 0, (Pgno)7, 0, "top1");121 test_lockTable(&child, 1, (Pgno)8, 1, "top2");122 123 /* Child should not accumulate its own locks */124 TEST_ASSERT_EQUAL_INT(0, child.nTableLock);125 TEST_ASSERT_NULL(child.aTableLock);126 127 /* Top-level should contain both locks in order */128 TEST_ASSERT_EQUAL_INT(2, top.nTableLock);129 TEST_ASSERT_NOT_NULL(top.aTableLock);130 131 TableLock *t = top.aTableLock;132 TEST_ASSERT_EQUAL_INT(0, t[0].iDb);133 TEST_ASSERT_EQUAL_INT(7, (int)t[0].iTab);134 TEST_ASSERT_EQUAL_INT(0, (int)t[0].isWriteLock);135 TEST_ASSERT_EQUAL_PTR("top1", t[0].zLockName);136 137 TEST_ASSERT_EQUAL_INT(1, t[1].iDb);138 TEST_ASSERT_EQUAL_INT(8, (int)t[1].iTab);139 TEST_ASSERT_EQUAL_INT(1, (int)t[1].isWriteLock);140 TEST_ASSERT_EQUAL_PTR("top2", t[1].zLockName);141 142 sqlite3DbFree(gDb, top.aTableLock);143}144 145/* Test 5: Stress allocation with many distinct entries */146void test_lockTable_stress_multiple_allocations(void){147 Parse p;148 initParse(&p);149 150 const char *name = "tab";151 const int N = 64; /* Enough to exercise multiple reallocations */152 for(int i=0; i<N; i++){153 int iDb = i % 3;154 Pgno iTab = (Pgno)(1000 + i);155 u8 isWrite = (i % 5 == 0) ? 1 : 0; /* some writes, mostly reads */156 test_lockTable(&p, iDb, iTab, isWrite, name);157 }158 159 TEST_ASSERT_EQUAL_INT(N, p.nTableLock);160 TEST_ASSERT_NOT_NULL(p.aTableLock);161 162 /* Spot check a few entries */163 TEST_ASSERT_EQUAL_INT(0, p.aTableLock[0].iDb);164 TEST_ASSERT_EQUAL_INT(1000, (int)p.aTableLock[0].iTab);165 TEST_ASSERT_EQUAL_INT(1, (int)p.aTableLock[0].isWriteLock);166 TEST_ASSERT_EQUAL_PTR(name, p.aTableLock[0].zLockName);167 168 TEST_ASSERT_EQUAL_INT(2, p.aTableLock[2].iDb);169 TEST_ASSERT_EQUAL_INT(1002, (int)p.aTableLock[2].iTab);170 TEST_ASSERT_EQUAL_INT(0, (int)p.aTableLock[2].isWriteLock);171 TEST_ASSERT_EQUAL_PTR(name, p.aTableLock[2].zLockName);172 173 TEST_ASSERT_EQUAL_INT((N-1)%3, p.aTableLock[N-1].iDb);174 TEST_ASSERT_EQUAL_INT(1000 + (N-1), (int)p.aTableLock[N-1].iTab);175 TEST_ASSERT_EQUAL_INT(((N-1)%5)==0 ? 1 : 0, (int)p.aTableLock[N-1].isWriteLock);176 TEST_ASSERT_EQUAL_PTR(name, p.aTableLock[N-1].zLockName);177 178 sqlite3DbFree(gDb, p.aTableLock);179}180 181int main(void) {182 UNITY_BEGIN();183 RUN_TEST(test_lockTable_basic_add_read_lock);184 RUN_TEST(test_lockTable_duplicate_does_not_add_but_upgrades_write);185 RUN_TEST(test_lockTable_multiple_distinct_entries);186 RUN_TEST(test_lockTable_uses_toplevel_from_child);187 RUN_TEST(test_lockTable_stress_multiple_allocations);188 return UNITY_END();189}