AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdio.h>4#include <stdlib.h>5#include <string.h>6 7/* Forward declaration of internal type and test wrapper from dbpage.c */8typedef struct DbpageTable DbpageTable;9int test_dbpageBeginTrans(DbpageTable *pTab);10 11/* Helper to run SQL and assert success */12static void exec_sql_ok(sqlite3 *db, const char *sql){13 char *zErr = 0;14 int rc = sqlite3_exec(db, sql, 0, 0, &zErr);15 if( rc!=SQLITE_OK ){16 fprintf(stderr, "SQL error (%d): %s\nSQL: %s\n", rc, zErr?zErr:"(null)", sql);17 }18 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_exec failed");19 sqlite3_free(zErr);20}21 22/* Get the DbpageTable* for a created temp virtual table named zTab */23static DbpageTable* get_dbpage_table(sqlite3 *db, const char *zSchema, const char *zTab){24 /* Ensure module is registered */25 int rc = sqlite3DbpageRegister(db);26 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);27 28 /* Create the vtab if it doesn't exist already */29 char sql[256];30 sqlite3_snprintf(sizeof(sql), sql, "CREATE VIRTUAL TABLE %s.%s USING sqlite_dbpage", zSchema, zTab);31 exec_sql_ok(db, sql);32 33 /* Find the Table object using internal API */34 Table *pT = sqlite3FindTable(db, zTab, zSchema);35 TEST_ASSERT_NOT_NULL_MESSAGE(pT, "sqlite3FindTable returned NULL for dbpage vtab");36 37 TEST_ASSERT_NOT_NULL_MESSAGE(pT->pVTable, "Table->pVTable is NULL");38 TEST_ASSERT_NOT_NULL_MESSAGE(pT->pVTable->pVtab, "VTable->pVtab is NULL");39 return (DbpageTable*)pT->pVTable->pVtab;40}41 42void setUp(void) {43 /* No-op */44}45 46void tearDown(void) {47 /* No-op */48}49 50/* Test 1: Basic success on a writable in-memory database */51void test_dbpageBeginTrans_ok_inmemory(void){52 sqlite3 *db = 0;53 int rc = sqlite3_open(":memory:", &db);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);55 TEST_ASSERT_NOT_NULL(db);56 57 DbpageTable *pTab = get_dbpage_table(db, "temp", "t1");58 59 rc = test_dbpageBeginTrans(pTab);60 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);61 62 sqlite3_close(db);63}64 65/* Test 2: Success with multiple writable databases attached (in-memory) */66void test_dbpageBeginTrans_ok_with_attach_memory(void){67 sqlite3 *db = 0;68 int rc = sqlite3_open(":memory:", &db);69 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);70 TEST_ASSERT_NOT_NULL(db);71 72 DbpageTable *pTab = get_dbpage_table(db, "temp", "t2");73 74 /* Attach an in-memory database as 'aux' (writable) */75 exec_sql_ok(db, "ATTACH DATABASE ':memory:' AS aux");76 77 rc = test_dbpageBeginTrans(pTab);78 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);79 80 /* Detach and cleanup */81 exec_sql_ok(db, "DETACH DATABASE aux");82 sqlite3_close(db);83}84 85/* Helper: create a small on-disk database file */86static void create_sqlite_file(const char *zPath){87 sqlite3 *db = 0;88 int rc = sqlite3_open(zPath, &db);89 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);90 exec_sql_ok(db, "PRAGMA journal_mode=OFF");91 exec_sql_ok(db, "CREATE TABLE IF NOT EXISTS t(x)");92 sqlite3_close(db);93}94 95/* Test 3: Failure when an attached database is opened read-only */96void test_dbpageBeginTrans_fail_on_readonly_attached(void){97 const char *zFile = "ro_attached.sqlite";98 99 /* Create the file (writable connection) then close */100 create_sqlite_file(zFile);101 102 sqlite3 *db = 0;103 int rc = sqlite3_open(":memory:", &db);104 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);105 106 DbpageTable *pTab = get_dbpage_table(db, "temp", "t3");107 108 /* Attach the file in read-only mode via URI */109 rc = sqlite3_exec(db,110 "ATTACH DATABASE 'file:ro_attached.sqlite?mode=ro' AS auxro", 0, 0, 0);111 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "ATTACH read-only database failed");112 113 /* This should attempt to begin a write transaction on all Btrees.114 Main (in-memory) succeeds, auxro (read-only) should fail. */115 rc = test_dbpageBeginTrans(pTab);116 TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);117 118 /* Cleanup */119 sqlite3_exec(db, "DETACH DATABASE auxro", 0, 0, 0);120 sqlite3_close(db);121 remove(zFile);122}123 124/* Test 4: Failure when main database is opened read-only */125void test_dbpageBeginTrans_fail_on_readonly_main(void){126 const char *zFile = "ro_main.sqlite";127 128 /* Create file */129 create_sqlite_file(zFile);130 131 /* Open read-only connection to this file */132 sqlite3 *db = 0;133 int rc = sqlite3_open_v2(zFile, &db, SQLITE_OPEN_READONLY, 0);134 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);135 TEST_ASSERT_NOT_NULL(db);136 137 /* Create the dbpage vtab in temp schema (allowed even with RO main) */138 DbpageTable *pTab = get_dbpage_table(db, "temp", "t4");139 140 /* This should fail because main Btree is read-only */141 rc = test_dbpageBeginTrans(pTab);142 TEST_ASSERT_EQUAL_INT(SQLITE_READONLY, rc);143 144 sqlite3_close(db);145 remove(zFile);146}147 148int main(void){149 UNITY_BEGIN();150 RUN_TEST(test_dbpageBeginTrans_ok_inmemory);151 RUN_TEST(test_dbpageBeginTrans_ok_with_attach_memory);152 RUN_TEST(test_dbpageBeginTrans_fail_on_readonly_attached);153 RUN_TEST(test_dbpageBeginTrans_fail_on_readonly_main);154 return UNITY_END();155}