AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Wrapper provided in the module for static function */7extern void test_releaseAllSavepoints(Pager *pPager);8 9/* Global flag to observe if xClose was called by sqlite3OsClose */10static int g_closeCalled = 0;11 12/* Minimal xClose implementation to observe closing behavior */13static int test_xClose(sqlite3_file *pFile){14 g_closeCalled++;15 if( pFile ){16 pFile->pMethods = 0; /* normal sqlite3OsClose will also clear this */17 }18 return SQLITE_OK;19}20 21/* sqlite3_io_methods used for our test sqlite3_file objects */22static sqlite3_io_methods g_TestIoMethods;23 24/* Helper: allocate an sqlite3_file and optionally attach our io_methods */25static sqlite3_file* makeTestFileWithMethods(int attachMethods){26 sqlite3_file *p = (sqlite3_file*)sqlite3_malloc(sizeof(sqlite3_file));27 TEST_ASSERT_NOT_NULL(p);28 memset(p, 0, sizeof(*p));29 if( attachMethods ){30 memset(&g_TestIoMethods, 0, sizeof(g_TestIoMethods));31 g_TestIoMethods.iVersion = 1;32 g_TestIoMethods.xClose = test_xClose;33 p->pMethods = &g_TestIoMethods;34 }else{35 p->pMethods = 0; /* Simulate in-memory journal or already-closed file */36 }37 return p;38}39 40/* Helper: initialize a Pager with nSave savepoints and valid Bitvecs */41static void initPagerWithSavepoints(Pager *pPager, int nSave){42 memset(pPager, 0, sizeof(*pPager));43 if( nSave>0 ){44 pPager->aSavepoint = (PagerSavepoint*)sqlite3_malloc(sizeof(PagerSavepoint)*nSave);45 TEST_ASSERT_NOT_NULL(pPager->aSavepoint);46 memset(pPager->aSavepoint, 0, sizeof(PagerSavepoint)*nSave);47 pPager->nSavepoint = nSave;48 for(int i=0; i<nSave; i++){49 pPager->aSavepoint[i].pInSavepoint = sqlite3BitvecCreate(128);50 TEST_ASSERT_NOT_NULL(pPager->aSavepoint[i].pInSavepoint);51 }52 }53 pPager->nSubRec = 123; /* some non-zero value to verify reset */54}55 56/* Unity required hooks */57void setUp(void) {58 g_closeCalled = 0;59}60void tearDown(void) {61 /* Nothing to teardown globally */62}63 64/* Test: Non-exclusive mode should close non-mem journal and reset all fields */65void test_releaseAllSavepoints_closes_nonmem_in_nonexclusive_and_resets(void){66 Pager p;67 initPagerWithSavepoints(&p, 3);68 p.exclusiveMode = 0; /* non-exclusive -> must close */69 p.sjfd = makeTestFileWithMethods(1); /* non-mem (custom methods) */70 71 test_releaseAllSavepoints(&p);72 73 /* Verify savepoints freed and counters reset */74 TEST_ASSERT_EQUAL_INT(0, p.nSavepoint);75 TEST_ASSERT_NULL(p.aSavepoint);76 TEST_ASSERT_EQUAL_INT(0, p.nSubRec);77 78 /* Verify the sub-journal was closed */79 TEST_ASSERT_EQUAL_INT(1, g_closeCalled);80 TEST_ASSERT_NOT_NULL(p.sjfd);81 TEST_ASSERT_NULL(p.sjfd->pMethods);82 83 /* Cleanup our allocated sqlite3_file container */84 sqlite3_free(p.sjfd);85}86 87/* Test: Exclusive mode should NOT close non-mem journal; still resets fields */88void test_releaseAllSavepoints_does_not_close_in_exclusive_with_nonmem(void){89 Pager p;90 initPagerWithSavepoints(&p, 2);91 p.exclusiveMode = 1; /* exclusive -> do not close unless in-memory */92 p.sjfd = makeTestFileWithMethods(1); /* non-mem (custom methods) */93 94 test_releaseAllSavepoints(&p);95 96 /* Verify savepoints freed and counters reset */97 TEST_ASSERT_EQUAL_INT(0, p.nSavepoint);98 TEST_ASSERT_NULL(p.aSavepoint);99 TEST_ASSERT_EQUAL_INT(0, p.nSubRec);100 101 /* Verify not closed */102 TEST_ASSERT_EQUAL_INT(0, g_closeCalled);103 TEST_ASSERT_NOT_NULL(p.sjfd);104 TEST_ASSERT_EQUAL_PTR(&g_TestIoMethods, p.sjfd->pMethods);105 106 /* Close and free our test file to clean up */107 sqlite3OsClose(p.sjfd); /* invokes our xClose */108 sqlite3_free(p.sjfd);109}110 111/* Test: Exclusive mode but in-memory journal -> function should attempt close; fields reset */112void test_releaseAllSavepoints_in_exclusive_with_inmemory_resets_and_safe_close(void){113 Pager p;114 initPagerWithSavepoints(&p, 1);115 p.exclusiveMode = 1; /* exclusive */116 p.sjfd = makeTestFileWithMethods(0); /* simulate in-memory/closed (pMethods==NULL) */117 118 test_releaseAllSavepoints(&p);119 120 /* Verify savepoints freed and counters reset */121 TEST_ASSERT_EQUAL_INT(0, p.nSavepoint);122 TEST_ASSERT_NULL(p.aSavepoint);123 TEST_ASSERT_EQUAL_INT(0, p.nSubRec);124 125 /* pMethods was NULL; sqlite3OsClose is a no-op in this case */126 TEST_ASSERT_EQUAL_INT(0, g_closeCalled);127 TEST_ASSERT_NOT_NULL(p.sjfd);128 TEST_ASSERT_NULL(p.sjfd->pMethods);129 130 sqlite3_free(p.sjfd);131}132 133/* Test: nSavepoint==0 but aSavepoint non-NULL is cleaned up and journal closed when allowed */134void test_releaseAllSavepoints_handles_zero_count_and_frees_array(void){135 Pager p;136 memset(&p, 0, sizeof(p));137 /* Create an array but set count to 0 */138 p.aSavepoint = (PagerSavepoint*)sqlite3_malloc(sizeof(PagerSavepoint));139 TEST_ASSERT_NOT_NULL(p.aSavepoint);140 memset(p.aSavepoint, 0, sizeof(PagerSavepoint));141 p.nSavepoint = 0;142 p.nSubRec = 7;143 p.exclusiveMode = 0; /* non-exclusive -> should close */144 p.sjfd = makeTestFileWithMethods(1);145 146 test_releaseAllSavepoints(&p);147 148 TEST_ASSERT_EQUAL_INT(0, p.nSavepoint);149 TEST_ASSERT_NULL(p.aSavepoint);150 TEST_ASSERT_EQUAL_INT(0, p.nSubRec);151 TEST_ASSERT_EQUAL_INT(1, g_closeCalled);152 TEST_ASSERT_NULL(p.sjfd->pMethods);153 154 sqlite3_free(p.sjfd);155}156 157int main(void) {158 UNITY_BEGIN();159 RUN_TEST(test_releaseAllSavepoints_closes_nonmem_in_nonexclusive_and_resets);160 RUN_TEST(test_releaseAllSavepoints_does_not_close_in_exclusive_with_nonmem);161 RUN_TEST(test_releaseAllSavepoints_in_exclusive_with_inmemory_resets_and_safe_close);162 RUN_TEST(test_releaseAllSavepoints_handles_zero_count_and_frees_array);163 return UNITY_END();164}