AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <stdlib.h>4#include <string.h>5 6/* Unity setup/teardown */7void setUp(void) {8 /* No-op */9}10void tearDown(void) {11 /* No-op */12}13 14/* Helper: execute SQL and assert SQLITE_OK */15static void exec_ok(sqlite3 *db, const char *sql){16 char *errmsg = NULL;17 int rc = sqlite3_exec(db, sql, 0, 0, &errmsg);18 if( rc!=SQLITE_OK ){19 const char *em = errmsg ? errmsg : "(null)";20 /* Provide context if it fails */21 TEST_FAIL_MESSAGE(em);22 }23 sqlite3_free(errmsg);24}25 26/* Helper: prepare a statement, step once, return int result (column 0) */27static int query_int(sqlite3 *db, const char *sql){28 sqlite3_stmt *stmt = NULL;29 int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);30 TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "prepare failed");31 rc = sqlite3_step(stmt);32 TEST_ASSERT_TRUE_MESSAGE(rc==SQLITE_ROW || rc==SQLITE_DONE, "step not ROW/DONE");33 int v = (rc==SQLITE_ROW) ? sqlite3_column_int(stmt, 0) : 0;34 sqlite3_finalize(stmt);35 return v;36}37 38/* Test 1: NULL pointer returns SQLITE_OK */39void test_sqlite3_backup_finish_null_returns_ok(void){40 int rc = sqlite3_backup_finish(NULL);41 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);42}43 44/* Test 2: finish immediately after init without stepping returns OK and dest usable */45void test_sqlite3_backup_finish_without_stepping(void){46 sqlite3 *src = NULL, *dst = NULL;47 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &src));48 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &dst));49 50 sqlite3_backup *b = sqlite3_backup_init(dst, "main", src, "main");51 TEST_ASSERT_NOT_NULL(b);52 53 int rc_finish = sqlite3_backup_finish(b);54 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc_finish);55 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_errcode(dst));56 57 /* Dest should be usable after finish (no lingering locks/transactions) */58 exec_ok(dst, "CREATE TABLE t_dest(x); INSERT INTO t_dest VALUES(1);");59 int cnt = query_int(dst, "SELECT COUNT(*) FROM t_dest;");60 TEST_ASSERT_EQUAL_INT(1, cnt);61 62 sqlite3_close(dst);63 sqlite3_close(src);64}65 66/* Test 3: If step hits SQLITE_BUSY (src in write txn), finish returns SQLITE_BUSY and sets dest errcode */67void test_sqlite3_backup_finish_propagates_busy_error(void){68 sqlite3 *src = NULL, *dst = NULL;69 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &src));70 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &dst));71 72 /* Put source into a write transaction so backup_step will see TRANS_WRITE */73 exec_ok(src, "BEGIN IMMEDIATE;");74 75 sqlite3_backup *b = sqlite3_backup_init(dst, "main", src, "main");76 TEST_ASSERT_NOT_NULL(b);77 78 /* Attempt a step - should return SQLITE_BUSY due to src write txn */79 int rc_step = sqlite3_backup_step(b, 1);80 TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc_step);81 82 /* Now finish - should return SQLITE_BUSY and set dest error code */83 int rc_finish = sqlite3_backup_finish(b);84 TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc_finish);85 TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, sqlite3_errcode(dst));86 87 /* Cleanup src transaction */88 exec_ok(src, "ROLLBACK;");89 90 sqlite3_close(dst);91 sqlite3_close(src);92}93 94/* Test 4: After a complete backup (DONE), finish returns SQLITE_OK and dest contains copied data */95void test_sqlite3_backup_finish_after_done_returns_ok_and_data_copied(void){96 sqlite3 *src = NULL, *dst = NULL;97 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &src));98 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &dst));99 100 /* Populate source */101 exec_ok(src, "CREATE TABLE t(a);"102 "INSERT INTO t VALUES(1),(2),(3);");103 104 sqlite3_backup *b = sqlite3_backup_init(dst, "main", src, "main");105 TEST_ASSERT_NOT_NULL(b);106 107 /* Copy all pages in one call */108 int rc_step = sqlite3_backup_step(b, -1);109 TEST_ASSERT_EQUAL_INT(SQLITE_DONE, rc_step);110 111 /* Finish should map SQLITE_DONE -> SQLITE_OK */112 int rc_finish = sqlite3_backup_finish(b);113 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc_finish);114 TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_errcode(dst));115 116 /* Verify data exists in destination */117 int cnt_dst = query_int(dst, "SELECT COUNT(*) FROM t;");118 TEST_ASSERT_EQUAL_INT(3, cnt_dst);119 120 sqlite3_close(dst);121 sqlite3_close(src);122}123 124int main(void){125 UNITY_BEGIN();126 RUN_TEST(test_sqlite3_backup_finish_null_returns_ok);127 RUN_TEST(test_sqlite3_backup_finish_without_stepping);128 RUN_TEST(test_sqlite3_backup_finish_propagates_busy_error);129 RUN_TEST(test_sqlite3_backup_finish_after_done_returns_ok_and_data_copied);130 return UNITY_END();131}