Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_main_sqlite3_create_collation_v2.c205 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Simple comparator implementations for registration */7static int cmp_by_mem(void* pCtx, int n1, const void* s1, int n2, const void* s2){8  int c = memcmp(s1, s2, (n1<n2)?n1:n2);9  if( c ) return c;10  return (n1 - n2);11}12static int cmp_by_mem_rev(void* pCtx, int n1, const void* s1, int n2, const void* s2){13  /* Reverse of cmp_by_mem for distinction */14  int c = memcmp(s2, s1, (n1<n2)?n1:n2);15  if( c ) return c;16  return (n2 - n1);17}18 19/* Destructor helpers */20static void del_inc(void* p){21  if( p ) (*(int*)p)++;22}23static void del_inc2(void* p){24  if( p ) (*(int*)p)++;25}26 27/* Unity setUp/tearDown */28void setUp(void) {29  /* No global setup required */30}31void tearDown(void) {32  /* No global teardown required */33}34 35/* Utility to open an in-memory database and assert success */36static sqlite3* open_db_or_fail(void){37  sqlite3 *db = 0;38  int rc = sqlite3_open(":memory:", &db);39  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, "sqlite3_open failed");40  TEST_ASSERT_NOT_NULL(db);41  return db;42}43 44static CollSeq* find_coll(sqlite3* db, int enc, const char* zName){45  return sqlite3FindCollSeq(db, (u8)enc, zName, 0);46}47 48/* Test: basic UTF-8 registration succeeds and sets fields */49void test_sqlite3_create_collation_v2_basic_utf8_ok(void){50  sqlite3 *db = open_db_or_fail();51  const char *name = "coll_basic_utf8";52  int rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, 0, cmp_by_mem, 0);53  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);54 55  CollSeq *p = find_coll(db, SQLITE_UTF8, name);56  TEST_ASSERT_NOT_NULL(p);57  TEST_ASSERT_EQUAL_PTR((void*)cmp_by_mem, (void*)p->xCmp);58  TEST_ASSERT_EQUAL_PTR(0, p->pUser);59  TEST_ASSERT_EQUAL_PTR(0, (void*)p->xDel);60 61  sqlite3_close(db);62}63 64/* Test: SQLITE_UTF16 alias maps to native encoding and comparator is set */65void test_sqlite3_create_collation_v2_utf16_alias_mapping(void){66  sqlite3 *db = open_db_or_fail();67  const char *name = "coll_utf16_alias";68  int rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF16, 0, cmp_by_mem, 0);69  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);70 71  /* Should be stored under native UTF16 encoding */72  CollSeq *p = find_coll(db, SQLITE_UTF16NATIVE, name);73  TEST_ASSERT_NOT_NULL(p);74  TEST_ASSERT_EQUAL_PTR((void*)cmp_by_mem, (void*)p->xCmp);75 76  sqlite3_close(db);77}78 79/* Test: SQLITE_UTF16_ALIGNED preserves aligned bit in stored CollSeq->enc */80void test_sqlite3_create_collation_v2_utf16_aligned_bit_preserved(void){81  sqlite3 *db = open_db_or_fail();82  const char *name = "coll_utf16_aligned";83  int rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF16_ALIGNED, 0, cmp_by_mem, 0);84  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);85 86  CollSeq *p = find_coll(db, SQLITE_UTF16NATIVE, name);87  TEST_ASSERT_NOT_NULL(p);88  TEST_ASSERT_EQUAL_PTR((void*)cmp_by_mem, (void*)p->xCmp);89  /* Verify aligned bit is set in p->enc */90  TEST_ASSERT_TRUE( (p->enc & SQLITE_UTF16_ALIGNED) != 0 );91 92  sqlite3_close(db);93}94 95/* Test: invalid encoding returns SQLITE_MISUSE */96void test_sqlite3_create_collation_v2_invalid_encoding_returns_misuse(void){97  sqlite3 *db = open_db_or_fail();98  const char *name = "coll_invalid_enc";99  int rc = sqlite3_create_collation_v2(db, name, 0 /* invalid */, 0, cmp_by_mem, 0);100  TEST_ASSERT_EQUAL_INT(SQLITE_MISUSE, rc);101  sqlite3_close(db);102}103 104/* Test: replacing an existing collation calls the old xDel exactly once */105void test_sqlite3_create_collation_v2_replace_calls_destructor_once(void){106  sqlite3 *db = open_db_or_fail();107  const char *name = "coll_replace_del";108  int delCount = 0;109  int rc;110 111  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, &delCount, cmp_by_mem, del_inc);112  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);113 114  /* Replace with a different comparator; use xDel=NULL so close() won't affect delCount */115  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, 0, cmp_by_mem_rev, 0);116  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);117 118  /* Old destructor should have been called exactly once */119  TEST_ASSERT_EQUAL_INT(1, delCount);120 121  /* Verify the collation now points to the new comparator */122  CollSeq *p = find_coll(db, SQLITE_UTF8, name);123  TEST_ASSERT_NOT_NULL(p);124  TEST_ASSERT_EQUAL_PTR((void*)cmp_by_mem_rev, (void*)p->xCmp);125 126  sqlite3_close(db);127}128 129/* Test: attempting to replace while there is an active VM returns SQLITE_BUSY and does not call xDel */130void test_sqlite3_create_collation_v2_busy_when_active_vm(void){131  sqlite3 *db = open_db_or_fail();132  const char *name = "coll_busy_case";133  int delCount = 0;134  int rc;135 136  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, &delCount, cmp_by_mem, del_inc);137  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);138 139  /* Create an active VM by stepping a simple SELECT to SQLITE_ROW and not finalizing yet */140  sqlite3_stmt *pStmt = 0;141  rc = sqlite3_prepare_v2(db, "SELECT 1", -1, &pStmt, 0);142  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);143  rc = sqlite3_step(pStmt);144  TEST_ASSERT_EQUAL_INT(SQLITE_ROW, rc);145 146  /* Now attempt to replace the collation: should return SQLITE_BUSY */147  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, 0, cmp_by_mem_rev, 0);148  TEST_ASSERT_EQUAL_INT(SQLITE_BUSY, rc);149  /* Destructor must not have been called */150  TEST_ASSERT_EQUAL_INT(0, delCount);151 152  /* Finalize the statement to clear the active VM */153  rc = sqlite3_finalize(pStmt);154  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);155 156  /* Now replacement should succeed; use xDel=NULL so we don't affect delCount on close */157  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, 0, cmp_by_mem_rev, 0);158  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);159  /* Old destructor should now have been called exactly once */160  TEST_ASSERT_EQUAL_INT(1, delCount);161 162  sqlite3_close(db);163}164 165/* Test: deleting a collation (xCompare==NULL) calls destructor and clears xCmp */166void test_sqlite3_create_collation_v2_delete_collation_clears_and_calls_destructor(void){167  sqlite3 *db = open_db_or_fail();168  const char *name = "coll_delete_case";169  int delCount = 0;170  int rc;171 172  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, &delCount, cmp_by_mem, del_inc);173  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);174 175  /* Ensure it exists */176  CollSeq *p = find_coll(db, SQLITE_UTF8, name);177  TEST_ASSERT_NOT_NULL(p);178  TEST_ASSERT_NOT_NULL(p->xCmp);179 180  /* Delete by setting xCompare==NULL */181  rc = sqlite3_create_collation_v2(db, name, SQLITE_UTF8, 0, 0, 0);182  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);183 184  /* Destructor called once */185  TEST_ASSERT_EQUAL_INT(1, delCount);186 187  /* Verify xCmp is cleared */188  p = find_coll(db, SQLITE_UTF8, name);189  TEST_ASSERT_NOT_NULL(p);190  TEST_ASSERT_EQUAL_PTR(0, (void*)p->xCmp);191 192  sqlite3_close(db);193}194 195int main(void) {196  UNITY_BEGIN();197  RUN_TEST(test_sqlite3_create_collation_v2_basic_utf8_ok);198  RUN_TEST(test_sqlite3_create_collation_v2_utf16_alias_mapping);199  RUN_TEST(test_sqlite3_create_collation_v2_utf16_aligned_bit_preserved);200  RUN_TEST(test_sqlite3_create_collation_v2_invalid_encoding_returns_misuse);201  RUN_TEST(test_sqlite3_create_collation_v2_replace_calls_destructor_once);202  RUN_TEST(test_sqlite3_create_collation_v2_busy_when_active_vm);203  RUN_TEST(test_sqlite3_create_collation_v2_delete_collation_clears_and_calls_destructor);204  return UNITY_END();205}