AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4 5/* The static function under test has a global wrapper named test_accessPayloadChecked */6extern int test_accessPayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf);7 8static sqlite3 *gDb = NULL;9 10void setUp(void) {11 /* Open an in-memory database for tests that need real Btree/BtShared */12 /* For tests that do not need it, this being open is harmless */13 if( gDb==NULL ){14 int rc = sqlite3_open(":memory:", &gDb);15 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);16 }17}18 19void tearDown(void) {20 if( gDb ){21 sqlite3_close(gDb);22 gDb = NULL;23 }24}25 26/* Helper: obtain the main database Btree from the opened connection */27static Btree* helperGetMainBtree(sqlite3 *db){28 /* aDb[0] is main db */29 TEST_ASSERT_NOT_NULL(db);30 TEST_ASSERT_TRUE(db->nDb>0);31 TEST_ASSERT_NOT_NULL(db->aDb);32 return db->aDb[0].pBt;33}34 35/* Test 1: When the cursor is CURSOR_INVALID, the function must return SQLITE_ABORT,36 and not modify the output buffer. */37void test_accessPayloadChecked_returns_abort_on_invalid(void) {38 BtCursor cur;39 memset(&cur, 0, sizeof(cur));40 cur.eState = CURSOR_INVALID; /* Immediate return path */41 42 unsigned char buf[16];43 memset(buf, 0xAA, sizeof(buf));44 45 int rc = test_accessPayloadChecked(&cur, /*offset=*/0, /*amt=*/8, buf);46 TEST_ASSERT_EQUAL_INT(SQLITE_ABORT, rc);47 48 /* Buffer must remain unchanged since accessPayload() is never called */49 for(size_t i=0; i<sizeof(buf); i++){50 TEST_ASSERT_EQUAL_UINT8(0xAA, buf[i]);51 }52}53 54/* Test 2: When the cursor is not invalid and is in CURSOR_FAULT, the wrapper should:55 - assert cursor owns BtShared (so we must satisfy mutex/db equality)56 - call btreeRestoreCursorPosition(), which returns cur.skipNext for CURSOR_FAULT57 - return that code and not touch the buffer58*/59void test_accessPayloadChecked_propagates_restorecode_on_fault(void) {60 /* Acquire a real Btree and BtShared to satisfy asserts (cursorOwnsBtShared) */61 Btree *pBtree = helperGetMainBtree(gDb);62 TEST_ASSERT_NOT_NULL(pBtree);63 BtShared *pBt = pBtree->pBt;64 TEST_ASSERT_NOT_NULL(pBt);65 66 /* Enter the Btree mutex so that cursorHoldsMutex() assertion passes */67 sqlite3BtreeEnter(pBtree);68 69 BtCursor cur;70 memset(&cur, 0, sizeof(cur));71 cur.pBtree = pBtree;72 cur.pBt = pBt;73 cur.eState = CURSOR_FAULT; /* >= CURSOR_REQUIRESEEK and trips early return in restore */74 cur.skipNext = 37; /* Expected rc from btreeRestoreCursorPosition */75 76 unsigned char out[8];77 memset(out, 0xBB, sizeof(out));78 79 int rc = test_accessPayloadChecked(&cur, 4, 4, out);80 TEST_ASSERT_EQUAL_INT(37, rc);81 /* The cursor should still be in FAULT state after the call (no change in early return) */82 TEST_ASSERT_EQUAL_INT(CURSOR_FAULT, cur.eState);83 /* The buffer should be untouched */84 for(size_t i=0; i<sizeof(out); i++){85 TEST_ASSERT_EQUAL_UINT8(0xBB, out[i]);86 }87 88 sqlite3BtreeLeave(pBtree);89}90 91int main(void) {92 UNITY_BEGIN();93 RUN_TEST(test_accessPayloadChecked_returns_abort_on_invalid);94 RUN_TEST(test_accessPayloadChecked_propagates_restorecode_on_fault);95 return UNITY_END();96}