Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_func_replaceFunc.c276 linesDownload Raw Back to tests
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 test wrapper exposed in the module */8void test_replaceFunc(sqlite3_context *context, int argc, sqlite3_value **argv);9 10static sqlite3 *gDb = NULL;11 12/* Helpers to manage sqlite3_value arguments */13static sqlite3_value* makeTextValue(sqlite3 *db, const char *z){14  sqlite3_value *v = sqlite3ValueNew(db);15  TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3ValueNew returned NULL");16  /* -1 means NUL-terminated; use SQLITE_TRANSIENT to copy into Mem */17  sqlite3ValueSetStr(v, -1, z, SQLITE_UTF8, SQLITE_TRANSIENT);18  return v;19}20 21static sqlite3_value* makeNullValue(sqlite3 *db){22  sqlite3_value *v = sqlite3ValueNew(db);23  TEST_ASSERT_NOT_NULL_MESSAGE(v, "sqlite3ValueNew returned NULL for NULL value");24  sqlite3VdbeMemSetNull((Mem*)v);25  return v;26}27 28/* Initialize a minimal sqlite3_context suitable for test_replaceFunc */29static void initContext(sqlite3_context *pCtx){30  memset(pCtx, 0, sizeof(*pCtx));31  /* Initialize result as NULL and attach db */32  pCtx->s.flags = MEM_Null;33  pCtx->s.db = gDb;34  pCtx->isError = 0;35}36 37/* Extract result text from context.s as a const char* (or NULL if NULL result) */38static const char* ctxResultText(sqlite3_context *pCtx){39  if( (pCtx->s.flags & MEM_Null)!=0 ){40    return NULL;41  }42  return (const char*)sqlite3_value_text((sqlite3_value*)&pCtx->s);43}44 45/* Clean up the result Mem inside the context between tests */46static void releaseContextResult(sqlite3_context *pCtx){47  sqlite3VdbeMemRelease(&pCtx->s);48  pCtx->s.flags = MEM_Null;49  pCtx->isError = 0;50}51 52/* Reference implementation for expected result (left-to-right, non-overlapping) */53static char* ref_replace(const char *A, const char *B, const char *C){54  if( A==NULL || B==NULL || C==NULL ) return NULL;55  size_t nA = strlen(A);56  size_t nB = strlen(B);57  size_t nC = strlen(C);58 59  if( nB==0 ){60    char *out = (char*)malloc(nA + 1);61    if(out==NULL) return NULL;62    memcpy(out, A, nA+1);63    return out;64  }65 66  /* Worst case: every char replaced and expansion occurs */67  size_t cap = nA + 1 + (nA * (nC>nB ? (nC-nB) : 0));68  char *out = (char*)malloc(cap);69  if(out==NULL) return NULL;70 71  size_t i=0, j=0;72  size_t limit = (nA>=nB)? (nA - nB) : 0;73  while( i<=limit ){74    if( A[i]==B[0] && memcmp(&A[i], B, nB)==0 ){75      memcpy(&out[j], C, nC);76      j += nC;77      i += nB;78    }else{79      out[j++] = A[i++];80    }81  }82  /* tail */83  while( i<nA ) out[j++] = A[i++];84  out[j] = '\0';85  return out;86}87 88/* Convenience to run replace and capture a heap copy of the result string (or NULL) */89static char* run_replace_and_copy(const char *A, const char *B, const char *C, int expectError, int *pErrCodeOut){90  sqlite3_context ctx;91  initContext(&ctx);92 93  sqlite3_value *argv[3];94  argv[0] = (A!=NULL) ? makeTextValue(gDb, A) : makeNullValue(gDb);95  argv[1] = (B!=NULL) ? makeTextValue(gDb, B) : makeNullValue(gDb);96  argv[2] = (C!=NULL) ? makeTextValue(gDb, C) : makeNullValue(gDb);97 98  test_replaceFunc(&ctx, 3, argv);99 100  const char *zRes = ctxResultText(&ctx);101  char *zCopy = NULL;102  if( zRes ){103    size_t n = strlen(zRes);104    zCopy = (char*)malloc(n+1);105    TEST_ASSERT_NOT_NULL_MESSAGE(zCopy, "malloc failed to copy result");106    memcpy(zCopy, zRes, n+1);107  }else{108    zCopy = NULL;109  }110 111  if( pErrCodeOut ) *pErrCodeOut = ctx.isError;112 113  /* Cleanup */114  releaseContextResult(&ctx);115  sqlite3ValueFree(argv[0]);116  sqlite3ValueFree(argv[1]);117  sqlite3ValueFree(argv[2]);118 119  if( expectError ){120    /* On error, result should be NULL */121    TEST_ASSERT_NULL(zCopy);122  }123  return zCopy;124}125 126void setUp(void) {127  int rc = sqlite3_open(":memory:", &gDb);128  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");129}130 131void tearDown(void) {132  if( gDb ){133    int rc = sqlite3_close(gDb);134    TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_close failed");135    gDb = NULL;136  }137}138 139/* Tests */140 141void test_replaceFunc_basic_single_char(void){142  const char *A = "hello world";143  const char *B = "l";144  const char *C = "L";145 146  char *got = run_replace_and_copy(A,B,C, 0, NULL);147  char *exp = ref_replace(A,B,C);148 149  TEST_ASSERT_NOT_NULL(got);150  TEST_ASSERT_NOT_NULL(exp);151  TEST_ASSERT_EQUAL_STRING(exp, got);152 153  free(got);154  free(exp);155}156 157void test_replaceFunc_no_match_returns_original(void){158  const char *A = "abcdef";159  const char *B = "xyz";160  const char *C = "Q";161 162  char *got = run_replace_and_copy(A,B,C, 0, NULL);163  TEST_ASSERT_NOT_NULL(got);164  TEST_ASSERT_EQUAL_STRING(A, got);165 166  free(got);167}168 169void test_replaceFunc_empty_pattern_returns_input(void){170  const char *A = "abc";171  const char *B = "";172  const char *C = "X";173 174  char *got = run_replace_and_copy(A,B,C, 0, NULL);175  TEST_ASSERT_NOT_NULL(got);176  TEST_ASSERT_EQUAL_STRING(A, got);177 178  free(got);179}180 181void test_replaceFunc_null_pattern_results_null(void){182  /* Pattern is NULL: function should leave result as NULL */183  char *got = run_replace_and_copy("abc", NULL, "x", 0, NULL);184  TEST_ASSERT_NULL(got);185  free(got);186}187 188void test_replaceFunc_null_input_results_null(void){189  char *got = run_replace_and_copy(NULL, "a", "b", 0, NULL);190  TEST_ASSERT_NULL(got);191  free(got);192}193 194void test_replaceFunc_null_replacement_results_null(void){195  char *got = run_replace_and_copy("abc", "a", NULL, 0, NULL);196  TEST_ASSERT_NULL(got);197  free(got);198}199 200void test_replaceFunc_shrink_pattern(void){201  const char *A = "abcabcabc";202  const char *B = "abc";203  const char *C = "x";204 205  char *got = run_replace_and_copy(A,B,C, 0, NULL);206  char *exp = ref_replace(A,B,C);207  TEST_ASSERT_NOT_NULL(got);208  TEST_ASSERT_NOT_NULL(exp);209  TEST_ASSERT_EQUAL_STRING(exp, got);210 211  free(got);212  free(exp);213}214 215void test_replaceFunc_overlap_non_overlapping_behavior(void){216  /* Replace "aa" with "a" in "aaaa" => "aa" (non-overlapping) */217  const char *A = "aaaa";218  const char *B = "aa";219  const char *C = "a";220  char *got = run_replace_and_copy(A,B,C, 0, NULL);221  TEST_ASSERT_NOT_NULL(got);222  TEST_ASSERT_EQUAL_STRING("aa", got);223  free(got);224}225 226void test_replaceFunc_expand_and_realloc(void){227  /* Ensure expansion path and realloc happen; many 'a' with "a"->"abcde" */228  const char *A = "xaxaxaxaxaxaxaxaxaxaxaxaxaxaxaxaxa";229  const char *B = "a";230  const char *C = "abcde";231 232  char *got = run_replace_and_copy(A,B,C, 0, NULL);233  char *exp = ref_replace(A,B,C);234 235  TEST_ASSERT_NOT_NULL(got);236  TEST_ASSERT_NOT_NULL(exp);237  TEST_ASSERT_EQUAL_STRING(exp, got);238 239  free(got);240  free(exp);241}242 243void test_replaceFunc_too_big_sets_error_and_null_result(void){244  /* Set a small LENGTH limit to force SQLITE_TOOBIG during expansion */245  int prev = sqlite3_limit(gDb, SQLITE_LIMIT_LENGTH, 50);246  /* Input with 11 matches of 'a' to exceed the limit:247     initial nOut = nStr+1 = 12 (since 11 'a's -> 11 + 1)248     each match adds (5-1)=4 -> 12 + 11*4 = 56, check uses nOut-1=55 > 50 -> error249  */250  const char *A = "aaaaaaaaaaa"; /* 11 'a' */251  const char *B = "a";252  const char *C = "aaaaa";253 254  int errCode = 0;255  char *got = run_replace_and_copy(A,B,C, 1, &errCode);256  TEST_ASSERT_NULL(got);257  TEST_ASSERT_EQUAL_INT(SQLITE_TOOBIG, errCode);258 259  /* Restore original limit */260  sqlite3_limit(gDb, SQLITE_LIMIT_LENGTH, prev);261}262 263int main(void) {264  UNITY_BEGIN();265  RUN_TEST(test_replaceFunc_basic_single_char);266  RUN_TEST(test_replaceFunc_no_match_returns_original);267  RUN_TEST(test_replaceFunc_empty_pattern_returns_input);268  RUN_TEST(test_replaceFunc_null_pattern_results_null);269  RUN_TEST(test_replaceFunc_null_input_results_null);270  RUN_TEST(test_replaceFunc_null_replacement_results_null);271  RUN_TEST(test_replaceFunc_shrink_pattern);272  RUN_TEST(test_replaceFunc_overlap_non_overlapping_behavior);273  RUN_TEST(test_replaceFunc_expand_and_realloc);274  RUN_TEST(test_replaceFunc_too_big_sets_error_and_null_result);275  return UNITY_END();276}