AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5#include <stdio.h>6 7/* Forward declaration of the function under test (ensure prototype is visible) */8extern int sqlite3InvokeBusyHandler(BusyHandler *p);9 10/* Globals to observe handler behavior */11static void *g_lastArg = NULL;12static int g_lastCount = -1;13static int g_callCount = 0;14 15/* Return sequence configuration for the test handler */16#define RET_SEQ_MAX 1617static int g_returnSequence[RET_SEQ_MAX];18static int g_returnSeqLen = 0;19static int g_returnSeqIndex = 0;20 21/* Test busy handler: records calls and returns configured values */22static int seqBusyHandler(void *arg, int n){23 g_callCount++;24 g_lastArg = arg;25 g_lastCount = n;26 27 if( g_returnSeqLen > 0 ){28 int idx = g_returnSeqIndex < g_returnSeqLen ? g_returnSeqIndex : (g_returnSeqLen - 1);29 int ret = g_returnSequence[idx];30 if( g_returnSeqIndex < g_returnSeqLen ) g_returnSeqIndex++;31 return ret;32 }33 /* Default behavior if no sequence configured: return non-zero (retry) */34 return 1;35}36 37/* Helper to configure the return sequence (does not reset call counters) */38static void handler_set_sequence(const int *vals, int len){39 if( len < 0 ) len = 0;40 if( len > RET_SEQ_MAX ) len = RET_SEQ_MAX;41 memset(g_returnSequence, 0, sizeof(g_returnSequence));42 if( vals && len > 0 ){43 memcpy(g_returnSequence, vals, sizeof(int)*len);44 }45 g_returnSeqLen = len;46 g_returnSeqIndex = 0;47}48 49void setUp(void) {50 g_lastArg = NULL;51 g_lastCount = -1;52 g_callCount = 0;53 memset(g_returnSequence, 0, sizeof(g_returnSequence));54 g_returnSeqLen = 0;55 g_returnSeqIndex = 0;56}57 58void tearDown(void) {59 /* Nothing to cleanup */60}61 62/* Test: xBusyHandler is NULL -> early return 0, nBusy unchanged, no call */63void test_sqlite3InvokeBusyHandler_null_handler_returns0_and_does_not_change_nBusy(void) {64 BusyHandler bh;65 memset(&bh, 0, sizeof(bh));66 bh.xBusyHandler = 0;67 bh.pBusyArg = &bh;68 bh.nBusy = 5;69 70 int rc = sqlite3InvokeBusyHandler(&bh);71 TEST_ASSERT_EQUAL_INT(0, rc);72 TEST_ASSERT_EQUAL_INT(5, bh.nBusy);73 TEST_ASSERT_EQUAL_INT(0, g_callCount);74}75 76/* Test: nBusy < 0 -> early return 0, handler not called, nBusy unchanged */77void test_sqlite3InvokeBusyHandler_negative_nBusy_early_return(void) {78 BusyHandler bh;79 memset(&bh, 0, sizeof(bh));80 bh.xBusyHandler = seqBusyHandler;81 bh.pBusyArg = &bh;82 bh.nBusy = -3;83 84 int rc = sqlite3InvokeBusyHandler(&bh);85 TEST_ASSERT_EQUAL_INT(0, rc);86 TEST_ASSERT_EQUAL_INT(-3, bh.nBusy);87 TEST_ASSERT_EQUAL_INT(0, g_callCount);88}89 90/* Test: handler returns 0 -> nBusy set to -1 and function returns 0 */91void test_sqlite3InvokeBusyHandler_handler_returns0_sets_nBusy_minus1(void) {92 BusyHandler bh;93 memset(&bh, 0, sizeof(bh));94 bh.xBusyHandler = seqBusyHandler;95 bh.pBusyArg = &bh;96 bh.nBusy = 0;97 98 int seq[] = {0};99 handler_set_sequence(seq, 1);100 101 int rc = sqlite3InvokeBusyHandler(&bh);102 TEST_ASSERT_EQUAL_INT(0, rc);103 TEST_ASSERT_EQUAL_INT(-1, bh.nBusy);104 TEST_ASSERT_EQUAL_INT(1, g_callCount);105 TEST_ASSERT_EQUAL_PTR(&bh, g_lastArg);106 TEST_ASSERT_EQUAL_INT(0, g_lastCount);107}108 109/* Test: handler returns non-zero -> nBusy increments and return value is propagated */110void test_sqlite3InvokeBusyHandler_handler_returns_nonzero_increments_and_returns_value(void) {111 BusyHandler bh;112 memset(&bh, 0, sizeof(bh));113 bh.xBusyHandler = seqBusyHandler;114 bh.pBusyArg = &bh;115 bh.nBusy = 2;116 117 int seq[] = {7};118 handler_set_sequence(seq, 1);119 120 int rc = sqlite3InvokeBusyHandler(&bh);121 TEST_ASSERT_EQUAL_INT(7, rc);122 TEST_ASSERT_EQUAL_INT(3, bh.nBusy); /* incremented from 2 to 3 */123 TEST_ASSERT_EQUAL_INT(1, g_callCount);124 TEST_ASSERT_EQUAL_PTR(&bh, g_lastArg);125 TEST_ASSERT_EQUAL_INT(2, g_lastCount);126}127 128/* Test: multiple invocations with non-zero returns increment nBusy and pass correct counts */129void test_sqlite3InvokeBusyHandler_multiple_retries_increment_nBusy_correctly(void) {130 BusyHandler bh;131 memset(&bh, 0, sizeof(bh));132 bh.xBusyHandler = seqBusyHandler;133 bh.pBusyArg = &bh;134 bh.nBusy = 4;135 136 int seq[] = {1,1,1};137 handler_set_sequence(seq, 3);138 139 int rc;140 141 rc = sqlite3InvokeBusyHandler(&bh);142 TEST_ASSERT_EQUAL_INT(1, rc);143 TEST_ASSERT_EQUAL_INT(5, bh.nBusy);144 TEST_ASSERT_EQUAL_INT(4, g_lastCount);145 146 rc = sqlite3InvokeBusyHandler(&bh);147 TEST_ASSERT_EQUAL_INT(1, rc);148 TEST_ASSERT_EQUAL_INT(6, bh.nBusy);149 TEST_ASSERT_EQUAL_INT(5, g_lastCount);150 151 rc = sqlite3InvokeBusyHandler(&bh);152 TEST_ASSERT_EQUAL_INT(1, rc);153 TEST_ASSERT_EQUAL_INT(7, bh.nBusy);154 TEST_ASSERT_EQUAL_INT(6, g_lastCount);155 156 TEST_ASSERT_EQUAL_INT(3, g_callCount);157}158 159/* Test: after a 0 return sets nBusy to -1, subsequent calls do not invoke handler and return 0 */160void test_sqlite3InvokeBusyHandler_after_zero_return_no_more_calls(void) {161 BusyHandler bh;162 memset(&bh, 0, sizeof(bh));163 bh.xBusyHandler = seqBusyHandler;164 bh.pBusyArg = &bh;165 bh.nBusy = 1;166 167 int seq0[] = {0};168 handler_set_sequence(seq0, 1);169 170 int rc = sqlite3InvokeBusyHandler(&bh);171 TEST_ASSERT_EQUAL_INT(0, rc);172 TEST_ASSERT_EQUAL_INT(-1, bh.nBusy);173 TEST_ASSERT_EQUAL_INT(1, g_callCount);174 175 /* Change the sequence; the handler should not be called again due to nBusy < 0 */176 int seq1[] = {1};177 handler_set_sequence(seq1, 1);178 179 rc = sqlite3InvokeBusyHandler(&bh);180 TEST_ASSERT_EQUAL_INT(0, rc);181 TEST_ASSERT_EQUAL_INT(-1, bh.nBusy);182 TEST_ASSERT_EQUAL_INT(1, g_callCount); /* still 1, no additional calls */183}184 185/* Test: verify pBusyArg and initial nBusy are passed to the handler correctly */186void test_sqlite3InvokeBusyHandler_handler_receives_correct_arguments(void) {187 BusyHandler bh;188 memset(&bh, 0, sizeof(bh));189 bh.xBusyHandler = seqBusyHandler;190 bh.pBusyArg = (void*)&bh; /* sentinel */191 bh.nBusy = 0;192 193 int seq[] = {1};194 handler_set_sequence(seq, 1);195 196 int rc = sqlite3InvokeBusyHandler(&bh);197 TEST_ASSERT_EQUAL_INT(1, rc);198 TEST_ASSERT_EQUAL_PTR(&bh, g_lastArg);199 TEST_ASSERT_EQUAL_INT(0, g_lastCount);200 TEST_ASSERT_EQUAL_INT(1, bh.nBusy); /* incremented after non-zero return */201}202 203/* Optional: handler returns 0 regardless of initial nBusy > 0: nBusy becomes -1 */204void test_sqlite3InvokeBusyHandler_zero_return_from_nonzero_initial_nBusy_sets_minus1(void) {205 BusyHandler bh;206 memset(&bh, 0, sizeof(bh));207 bh.xBusyHandler = seqBusyHandler;208 bh.pBusyArg = &bh;209 bh.nBusy = 10;210 211 int seq[] = {0};212 handler_set_sequence(seq, 1);213 214 int rc = sqlite3InvokeBusyHandler(&bh);215 TEST_ASSERT_EQUAL_INT(0, rc);216 TEST_ASSERT_EQUAL_INT(-1, bh.nBusy);217 TEST_ASSERT_EQUAL_INT(1, g_callCount);218 TEST_ASSERT_EQUAL_INT(10, g_lastCount);219}220 221int main(void) {222 UNITY_BEGIN();223 RUN_TEST(test_sqlite3InvokeBusyHandler_null_handler_returns0_and_does_not_change_nBusy);224 RUN_TEST(test_sqlite3InvokeBusyHandler_negative_nBusy_early_return);225 RUN_TEST(test_sqlite3InvokeBusyHandler_handler_returns0_sets_nBusy_minus1);226 RUN_TEST(test_sqlite3InvokeBusyHandler_handler_returns_nonzero_increments_and_returns_value);227 RUN_TEST(test_sqlite3InvokeBusyHandler_multiple_retries_increment_nBusy_correctly);228 RUN_TEST(test_sqlite3InvokeBusyHandler_after_zero_return_no_more_calls);229 RUN_TEST(test_sqlite3InvokeBusyHandler_handler_receives_correct_arguments);230 RUN_TEST(test_sqlite3InvokeBusyHandler_zero_return_from_nonzero_initial_nBusy_sets_minus1);231 return UNITY_END();232}