AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdio.h>5 6/* Helper macros for portability */7#ifndef UNUSED_PARAMETER8#define UNUSED_PARAMETER(x) (void)(x)9#endif10 11/* Forward declarations for helpers */12static sqlite3* helper_open_memory_db(void);13static void helper_close_db(sqlite3 *db);14static void helper_commit_if_needed(Btree *p);15 16/* Unity hooks */17void setUp(void) {18 /* nothing */19}20void tearDown(void) {21 /* nothing */22}23 24/* Helpers */25 26static sqlite3* helper_open_memory_db(void){27 sqlite3 *db = NULL;28 int rc = sqlite3_open(":memory:", &db);29 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);30 TEST_ASSERT_NOT_NULL(db);31 return db;32}33 34static void helper_close_db(sqlite3 *db){35 if( db ){36 int rc = sqlite3_close(db);37 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);38 }39}40 41static void helper_commit_if_needed(Btree *p){42 if( p ){43 if( p->inTrans!=TRANS_NONE ){44 int rc = sqlite3BtreeCommit(p);45 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);46 TEST_ASSERT_EQUAL_INT(TRANS_NONE, p->inTrans);47 }48 }49}50 51/* Tests */52 53void test_sqlite3BtreeBeginTrans_read_ok_and_schema_version(void){54 sqlite3 *db = helper_open_memory_db();55 56 /* Get main database Btree */57 TEST_ASSERT_NOT_NULL(db);58 TEST_ASSERT_TRUE(db->nDb>0);59 Btree *p = db->aDb[0].pBt;60 TEST_ASSERT_NOT_NULL(p);61 62 int schemaVer = -1;63 int rc = sqlite3BtreeBeginTrans(p, 0, &schemaVer);64 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);65 TEST_ASSERT_EQUAL_INT(TRANS_READ, p->inTrans);66 67 /* Expect schema version read from page1 offset 40 (cookie) which should be 0 on fresh db */68 u32 expectVer = get4byte(&p->pBt->pPage1->aData[40]);69 TEST_ASSERT_EQUAL_INT(expectVer, (u32)schemaVer);70 71 helper_commit_if_needed(p);72 helper_close_db(db);73}74 75void test_sqlite3BtreeBeginTrans_read_idempotent(void){76 sqlite3 *db = helper_open_memory_db();77 Btree *p = db->aDb[0].pBt;78 TEST_ASSERT_NOT_NULL(p);79 80 int sv1 = -1;81 int rc1 = sqlite3BtreeBeginTrans(p, 0, &sv1);82 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc1);83 TEST_ASSERT_EQUAL_INT(TRANS_READ, p->inTrans);84 85 /* Second read begin should be a no-op that still returns OK */86 int sv2 = -1;87 int rc2 = sqlite3BtreeBeginTrans(p, 0, &sv2);88 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc2);89 TEST_ASSERT_EQUAL_INT(TRANS_READ, p->inTrans);90 91 /* Both schema versions should match the current cookie */92 u32 expectVer = get4byte(&p->pBt->pPage1->aData[40]);93 TEST_ASSERT_EQUAL_INT(expectVer, (u32)sv1);94 TEST_ASSERT_EQUAL_INT(expectVer, (u32)sv2);95 96 helper_commit_if_needed(p);97 helper_close_db(db);98}99 100void test_sqlite3BtreeBeginTrans_write_ok_state_flags(void){101 sqlite3 *db = helper_open_memory_db();102 Btree *p = db->aDb[0].pBt;103 TEST_ASSERT_NOT_NULL(p);104 105 int schemaVer = -1;106 int rc = sqlite3BtreeBeginTrans(p, 1, &schemaVer);107 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);108 109 /* Verify Btree and BtShared state indicate write transaction */110 TEST_ASSERT_EQUAL_INT(TRANS_WRITE, p->inTrans);111 TEST_ASSERT_EQUAL_INT(TRANS_WRITE, p->pBt->inTransaction);112 113 helper_commit_if_needed(p);114 helper_close_db(db);115}116 117void test_sqlite3BtreeBeginTrans_schema_version_matches_cookie(void){118 sqlite3 *db = helper_open_memory_db();119 /* Change schema_version via PRAGMA and verify the output from sqlite3BtreeBeginTrans */120 int rc = sqlite3_exec(db, "PRAGMA schema_version=12345;", 0, 0, 0);121 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);122 123 Btree *p = db->aDb[0].pBt;124 TEST_ASSERT_NOT_NULL(p);125 126 int outVer = -1;127 rc = sqlite3BtreeBeginTrans(p, 0, &outVer);128 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);129 /* Now the schema cookie should be 12345 */130 u32 expectVer = get4byte(&p->pBt->pPage1->aData[40]);131 TEST_ASSERT_EQUAL_UINT32((u32)12345, expectVer);132 TEST_ASSERT_EQUAL_UINT32(expectVer, (u32)outVer);133 134 helper_commit_if_needed(p);135 helper_close_db(db);136}137 138void test_sqlite3BtreeBeginTrans_readonly_write_fails(void){139 /* Create a disk DB, then reopen read-only and try to begin a write tx */140 const char *fname = "test_ro_btree.db";141 sqlite3 *dbw = NULL;142 int rc = sqlite3_open(fname, &dbw);143 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);144 /* Create some content to ensure the file exists with a valid header */145 rc = sqlite3_exec(dbw, "CREATE TABLE t(x);", 0, 0, 0);146 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);147 rc = sqlite3_close(dbw);148 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);149 150 sqlite3 *dbr = NULL;151 rc = sqlite3_open_v2(152 "file:test_ro_btree.db?mode=ro&cache=private",153 &dbr,154 SQLITE_OPEN_READONLY | SQLITE_OPEN_URI,155 NULL156 );157 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);158 159 /* Obtain Btree and attempt write transaction */160 Btree *p = dbr->aDb[0].pBt;161 TEST_ASSERT_NOT_NULL(p);162 int sv = -1;163 rc = sqlite3BtreeBeginTrans(p, 1, &sv);164 TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);165 166 /* Should not be in a write transaction */167 TEST_ASSERT_NOT_EQUAL(TRANS_WRITE, p->inTrans);168 169 helper_commit_if_needed(p);170 helper_close_db(dbr);171 172 /* Cleanup the file (best-effort) */173 sqlite3_vfs *pVfs = sqlite3_vfs_find(NULL);174 if( pVfs && pVfs->xDelete ){175 pVfs->xDelete(pVfs, fname, 0);176 }177}178 179int main(void){180 UNITY_BEGIN();181 RUN_TEST(test_sqlite3BtreeBeginTrans_read_ok_and_schema_version);182 RUN_TEST(test_sqlite3BtreeBeginTrans_read_idempotent);183 RUN_TEST(test_sqlite3BtreeBeginTrans_write_ok_state_flags);184 RUN_TEST(test_sqlite3BtreeBeginTrans_schema_version_matches_cookie);185 RUN_TEST(test_sqlite3BtreeBeginTrans_readonly_write_fails);186 return UNITY_END();187}