AryaWu/sqlite
0
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* Globals used by callbacks to count invocations */7static int g_coll_needed_calls = 0;8static int g_coll_needed_other_calls = 0;9 10/* A simple comparator usable for all encodings (compares raw bytes) */11static int test_simple_cmp(void *pCtx,12 int nA, const void *a,13 int nB, const void *b){14 int n = (nA < nB) ? nA : nB;15 int c = memcmp(a, b, (size_t)n);16 if( c!=0 ) return c;17 return nA - nB;18}19 20/* Collation-needed callback that registers the requested collation21** in the same encoding as requested (enc).22*/23static void coll_needed_register_same(void *pArg, sqlite3 *db, int enc, const char *zName){24 (void)pArg;25 /* Only act for specific test names to avoid side-effects */26 if( strcmp(zName, "u_test_coll_needed_ok")==0 ){27 sqlite3_create_collation(db, zName, enc, 0, test_simple_cmp);28 g_coll_needed_calls++;29 }30}31 32/* Collation-needed callback that registers the collation only in UTF8,33** regardless of the requested encoding. Used to test synthCollSeq().34*/35static void coll_needed_register_other(void *pArg, sqlite3 *db, int enc, const char *zName){36 (void)pArg; (void)enc;37 if( strcmp(zName, "u_test_synth")==0 ){38 sqlite3_create_collation(db, zName, SQLITE_UTF8, 0, test_simple_cmp);39 g_coll_needed_other_calls++;40 }41}42 43/* Utility to initialize a Parse object */44static void initParse(Parse *pParse, sqlite3 *db){45 memset(pParse, 0, sizeof(*pParse));46 pParse->db = db;47}48 49/* Unity setup/teardown */50void setUp(void) {51 g_coll_needed_calls = 0;52 g_coll_needed_other_calls = 0;53}54void tearDown(void) {55 /* nothing */56}57 58/* Test 1: Passing NULL pColl returns SQLITE_OK */59void test_sqlite3CheckCollSeq_null_collseq_returns_ok(void){60 sqlite3 *db = 0;61 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));62 TEST_ASSERT_NOT_NULL(db);63 64 Parse p;65 initParse(&p, db);66 int rc = sqlite3CheckCollSeq(&p, NULL);67 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);68 TEST_ASSERT_EQUAL_INT(0, p.rc);69 if( p.zErrMsg ){70 sqlite3DbFree(db, p.zErrMsg);71 }72 73 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_close(db));74}75 76/* Test 2: Already-defined collation returns OK and does not invoke factory */77void test_sqlite3CheckCollSeq_defined_collseq_no_factory_invocation(void){78 sqlite3 *db = 0;79 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));80 TEST_ASSERT_NOT_NULL(db);81 82 /* Define a collation explicitly */83 const char *zName = "u_test_predefined";84 TEST_ASSERT_EQUAL(SQLITE_OK,85 sqlite3_create_collation(db, zName, ENC(db), 0, test_simple_cmp));86 87 /* Obtain the native-encoding CollSeq pointer; should be defined (xCmp!=0) */88 CollSeq *pColl = sqlite3FindCollSeq(db, ENC(db), zName, 0);89 TEST_ASSERT_NOT_NULL(pColl);90 TEST_ASSERT_NOT_NULL(pColl->xCmp);91 92 /* Install a collation-needed callback that would increment a counter if called */93 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_collation_needed(db, NULL, coll_needed_register_same));94 95 Parse p;96 initParse(&p, db);97 int rc = sqlite3CheckCollSeq(&p, pColl);98 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);99 TEST_ASSERT_EQUAL_INT(0, p.rc);100 TEST_ASSERT_EQUAL_INT(0, g_coll_needed_calls); /* Must not be invoked */101 if( p.zErrMsg ){102 sqlite3DbFree(db, p.zErrMsg);103 }104 105 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_close(db));106}107 108/* Test 3: Undefined collation with working factory should succeed and define xCmp */109void test_sqlite3CheckCollSeq_collation_needed_success(void){110 sqlite3 *db = 0;111 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));112 TEST_ASSERT_NOT_NULL(db);113 114 const char *zName = "u_test_coll_needed_ok";115 /* Create an entry (xCmp==0 initially) for the native encoding */116 CollSeq *pColl = sqlite3FindCollSeq(db, ENC(db), zName, 1);117 TEST_ASSERT_NOT_NULL(pColl);118 TEST_ASSERT_EQUAL_PTR(zName, pColl->zName); /* The zName is stored in the entry */119 TEST_ASSERT_NULL(pColl->xCmp);120 121 /* Install a collation-needed callback that registers this name in the requested encoding */122 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_collation_needed(db, NULL, coll_needed_register_same));123 124 Parse p;125 initParse(&p, db);126 int rc = sqlite3CheckCollSeq(&p, pColl);127 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);128 TEST_ASSERT_EQUAL_INT(0, p.rc);129 TEST_ASSERT_TRUE(g_coll_needed_calls >= 1);130 TEST_ASSERT_NOT_NULL(pColl->xCmp); /* Now defined */131 if( p.zErrMsg ){132 sqlite3DbFree(db, p.zErrMsg);133 }134 135 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_close(db));136}137 138/* Test 4: Undefined collation with no factory should return error and set parse rc */139void test_sqlite3CheckCollSeq_collation_needed_failure_sets_error(void){140 sqlite3 *db = 0;141 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));142 TEST_ASSERT_NOT_NULL(db);143 144 const char *zName = "u_test_coll_missing";145 CollSeq *pColl = sqlite3FindCollSeq(db, ENC(db), zName, 1);146 TEST_ASSERT_NOT_NULL(pColl);147 TEST_ASSERT_NULL(pColl->xCmp);148 149 /* No callback installed */150 151 Parse p;152 initParse(&p, db);153 int rc = sqlite3CheckCollSeq(&p, pColl);154 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR, rc);155 TEST_ASSERT_EQUAL_INT(SQLITE_ERROR_MISSING_COLLSEQ, p.rc);156 TEST_ASSERT_NOT_NULL(p.zErrMsg);157 if( p.zErrMsg ){158 sqlite3DbFree(db, p.zErrMsg);159 }160 161 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_close(db));162}163 164/* Test 5: Synthesize from other encoding when requested encoding is unavailable */165void test_sqlite3CheckCollSeq_synthesizes_from_other_encoding(void){166 sqlite3 *db = 0;167 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_open(":memory:", &db));168 TEST_ASSERT_NOT_NULL(db);169 170 /* Set DB native encoding to UTF16LE */171 sqlite3SetTextEncoding(db, SQLITE_UTF16LE);172 TEST_ASSERT_EQUAL_INT(SQLITE_UTF16LE, ENC(db));173 174 const char *zName = "u_test_synth";175 /* Create the native-encoding entry with xCmp==0 */176 CollSeq *pColl = sqlite3FindCollSeq(db, ENC(db), zName, 1);177 TEST_ASSERT_NOT_NULL(pColl);178 TEST_ASSERT_NULL(pColl->xCmp);179 180 /* Install a callback that registers only UTF8 variant, forcing synthesis */181 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_collation_needed(db, NULL, coll_needed_register_other));182 183 Parse p;184 initParse(&p, db);185 int rc = sqlite3CheckCollSeq(&p, pColl);186 TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);187 TEST_ASSERT_EQUAL_INT(0, p.rc);188 TEST_ASSERT_TRUE(g_coll_needed_other_calls >= 1);189 TEST_ASSERT_NOT_NULL(pColl->xCmp); /* Should be synthesized */190 if( p.zErrMsg ){191 sqlite3DbFree(db, p.zErrMsg);192 }193 194 TEST_ASSERT_EQUAL(SQLITE_OK, sqlite3_close(db));195}196 197/* Main runner */198int main(void){199 UNITY_BEGIN();200 RUN_TEST(test_sqlite3CheckCollSeq_null_collseq_returns_ok);201 RUN_TEST(test_sqlite3CheckCollSeq_defined_collseq_no_factory_invocation);202 RUN_TEST(test_sqlite3CheckCollSeq_collation_needed_success);203 RUN_TEST(test_sqlite3CheckCollSeq_collation_needed_failure_sets_error);204 RUN_TEST(test_sqlite3CheckCollSeq_synthesizes_from_other_encoding);205 return UNITY_END();206}