Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_fillInCell.c326 linesDownload Raw Back to tests
1#include "sqliteInt.h"2#include "unity.h"3#include <string.h>4#include <stdlib.h>5 6/* The wrapper provided in the module for the static function. */7int test_fillInCell(8  MemPage *pPage,9  unsigned char *pCell,10  const BtreePayload *pX,11  int *pnSize12);13 14/* Local stub for MemPage.xParseCell used by fillInCell() debug asserts.15   It parses the header we write in tests and fills CellInfo accordingly. */16static void test_xParseCell_stub(MemPage *pPage, u8 *pCell, CellInfo *pInfo){17  memset(pInfo, 0, sizeof(*pInfo));18  u8 *p = pCell + pPage->childPtrSize;19  /* parse varint payload-size (we only need small sizes for tests) */20  u32 nPayload = 0;21  u8 c = *p++;22  if( c<0x80 ){23    nPayload = c;24  }else{25    /* Support a few bytes; our tests only use small values. */26    nPayload = (c & 0x7f);27    while( (*p & 0x80) && (p - pCell) < 10 ){28      nPayload = (nPayload<<7) | (*p & 0x7f);29      p++;30    }31    nPayload = (nPayload<<7) | (*p & 0x7f);32    p++;33  }34  pInfo->nPayload = nPayload;35 36  if( pPage->intKeyLeaf ){37    /* parse rowid varint (small) */38    u64 key = 0;39    int i = 0;40    u8 b;41    do{42      b = *p++;43      key = (key<<7) | (b & 0x7f);44      i++;45    }while( (b & 0x80) && i<9 );46    pInfo->nKey = (i64)key;47  }else{48    /* For index pages, CellInfo.nKey is the record size (nPayload) */49    pInfo->nKey = (i64)nPayload;50  }51 52  pInfo->pPayload = p;53  /* In our tests, we ensure nPayload <= maxLocal (no overflow) */54  pInfo->nLocal = nPayload;55 56  int nHeader = (int)(pInfo->pPayload - pCell);57  int nSize = nHeader + (int)nPayload;58  if( nSize<4 ) nSize = 4;59  pInfo->nSize = (u16)nSize;60}61 62/* Helper to allocate and initialize a BtShared+MemPage with minimally63   required fields for local cell (no-overflow) use. */64typedef struct TestPage {65  BtShared *pBt;66  MemPage  *pPage;67  u8       *aPage;68  sqlite3_mutex *mutex;69} TestPage;70 71static void freeTestPage(TestPage *tp){72  if( !tp ) return;73  if( tp->mutex ){74    sqlite3_mutex_leave(tp->mutex);75    sqlite3_mutex_free(tp->mutex);76  }77  if( tp->aPage ) sqlite3_free(tp->aPage);78  if( tp->pPage ) sqlite3_free(tp->pPage);79  if( tp->pBt ) sqlite3_free(tp->pBt);80  memset(tp, 0, sizeof(*tp));81}82 83static void initTestPage(TestPage *tp, int isIntKeyLeaf){84  memset(tp, 0, sizeof(*tp));85  tp->pBt = (BtShared*)sqlite3MallocZero(sizeof(BtShared));86  TEST_ASSERT_NOT_NULL(tp->pBt);87  tp->pBt->pageSize = 4096;88  tp->pBt->usableSize = 4096; /* reserved bytes = 0 for tests */89 90  tp->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);91  TEST_ASSERT_NOT_NULL(tp->mutex);92  tp->pBt->mutex = tp->mutex;93 94  tp->aPage = (u8*)sqlite3MallocZero(tp->pBt->pageSize);95  TEST_ASSERT_NOT_NULL(tp->aPage);96 97  tp->pPage = (MemPage*)sqlite3MallocZero(sizeof(MemPage));98  TEST_ASSERT_NOT_NULL(tp->pPage);99  tp->pPage->pBt = tp->pBt;100  tp->pPage->aData = tp->aPage;101  tp->pPage->aDataEnd = tp->aPage + tp->pBt->pageSize;102  tp->pPage->childPtrSize = 0; /* leaf */103  tp->pPage->leaf = 1;104  tp->pPage->xParseCell = test_xParseCell_stub;105 106  if( isIntKeyLeaf ){107    tp->pPage->intKey = 1;108    tp->pPage->intKeyLeaf = 1;109    /* Generous maxLocal/minLocal so tests stay local */110    tp->pPage->maxLocal = 4000;111    tp->pPage->minLocal = 1000;112  }else{113    tp->pPage->intKey = 0;114    tp->pPage->intKeyLeaf = 0;115    tp->pPage->maxLocal = 4000;116    tp->pPage->minLocal = 1000;117  }118 119  /* Hold the mutex as required by fillInCell assertions */120  sqlite3_mutex_enter(tp->mutex);121}122 123/* Helpers for varints used in validation */124static int writeVarint32(u8 *p, u32 v){125  /* For our small test values, this is enough: fits in one byte if <128 */126  if( v<128 ){ p[0] = (u8)v; return 1; }127  /* Fallback multi-byte (not expected to be used in tests) */128  int n = 0;129  u8 buf[5];130  do{131    buf[n++] = (u8)(v & 0x7f);132    v >>= 7;133  }while( v );134  int i, j=0;135  for(i=n-1; i>=0; i--){136    p[j++] = buf[i] | (i?0x80:0x00);137  }138  return j;139}140 141static int writeVarint64(u8 *p, u64 v){142  /* For small test rowids (<128) this is one byte */143  if( v<128 ){ p[0] = (u8)v; return 1; }144  /* Fallback simple implementation */145  u8 buf[10];146  int n=0, i, j=0;147  do{148    buf[n++] = (u8)(v & 0x7f);149    v >>= 7;150  }while( v );151  for(i=n-1; i>=0; i--){152    p[j++] = buf[i] | (i?0x80:0x00);153  }154  return j;155}156 157/* Unity fixtures */158void setUp(void){159  /* Ensure SQLite core is initialized for mutex subsystem */160  sqlite3_initialize();161}162 163void tearDown(void){164  /* nothing */165}166 167/* Test 1: intkey leaf page with small payload and rowid */168void test_fillInCell_intkey_basic(void){169  TestPage tp;170  initTestPage(&tp, 1);171 172  unsigned char cell[64];173  memset(cell, 0xCC, sizeof(cell));174  int cellSize = -1;175 176  /* Prepare payload: nData=3 ("abc"), nZero=0, nKey(rowid)=5 */177  BtreePayload x;178  memset(&x, 0, sizeof(x));179  x.pData = (void*)"abc";180  x.nData = 3;181  x.nZero = 0;182  x.nKey = 5;183 184  int rc = test_fillInCell(tp.pPage, cell, &x, &cellSize);185  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);186 187  /* Expect header: varint(3)=0x03, varint(5)=0x05; payload "abc" */188  int hdr = 0;189  u8 expect[64];190  hdr += writeVarint32(expect+hdr, 3);191  hdr += writeVarint64(expect+hdr, 5);192  int total = hdr + 3;193  if( total<4 ) total = 4;194 195  TEST_ASSERT_EQUAL_INT(total, cellSize);196  /* Check header bytes */197  TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, cell, hdr);198  /* Check payload bytes */199  TEST_ASSERT_EQUAL_UINT8('a', cell[hdr+0]);200  TEST_ASSERT_EQUAL_UINT8('b', cell[hdr+1]);201  TEST_ASSERT_EQUAL_UINT8('c', cell[hdr+2]);202 203  freeTestPage(&tp);204}205 206/* Test 2: intkey leaf with header+payload < 4 triggers 4-byte minimum */207void test_fillInCell_intkey_min4(void){208  TestPage tp;209  initTestPage(&tp, 1);210 211  unsigned char cell[64];212  memset(cell, 0xEE, sizeof(cell));213  int cellSize = -1;214 215  /* payload size 1 ("X"), key 1 -> hdr 2 bytes + payload 1 = 3 -> padded to 4 */216  BtreePayload x;217  memset(&x, 0, sizeof(x));218  x.pData = (void*)"X";219  x.nData = 1;220  x.nZero = 0;221  x.nKey = 1;222 223  int rc = test_fillInCell(tp.pPage, cell, &x, &cellSize);224  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);225 226  int hdr = 0;227  u8 expect[64];228  hdr += writeVarint32(expect+hdr, 1);229  hdr += writeVarint64(expect+hdr, 1);230  int total = hdr + 1;231  if( total<4 ) total = 4;232 233  TEST_ASSERT_EQUAL_INT(4, cellSize);234  /* Check header */235  TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, cell, hdr);236  /* First data byte */237  TEST_ASSERT_EQUAL_UINT8('X', cell[hdr+0]);238  /* The function pads to 4 by setting pPayload[nPayload] = 0 */239  if( hdr+1 < 4 ){240    TEST_ASSERT_EQUAL_UINT8(0x00, cell[hdr+1]);241  }242 243  freeTestPage(&tp);244}245 246/* Test 3: index leaf (non-intkey): header only includes varint(nKey), then key bytes */247void test_fillInCell_index_basic(void){248  TestPage tp;249  initTestPage(&tp, 0); /* non-intkey (index leaf) */250 251  unsigned char cell[64];252  memset(cell, 0xAA, sizeof(cell));253  int cellSize = -1;254 255  const char *key = "xyz";256  BtreePayload x;257  memset(&x, 0, sizeof(x));258  x.pKey = (void*)key;259  x.nKey = 3;260  x.pData = 0; x.nData = 0; x.nZero = 0;261 262  int rc = test_fillInCell(tp.pPage, cell, &x, &cellSize);263  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);264 265  int hdr = 0;266  u8 expect[64];267  hdr += writeVarint32(expect+hdr, 3);268  int total = hdr + 3;269  if( total<4 ) total = 4;270 271  TEST_ASSERT_EQUAL_INT(total, cellSize);272  TEST_ASSERT_EQUAL_UINT8_ARRAY(expect, cell, hdr);273  TEST_ASSERT_EQUAL_UINT8('x', cell[hdr+0]);274  TEST_ASSERT_EQUAL_UINT8('y', cell[hdr+1]);275  TEST_ASSERT_EQUAL_UINT8('z', cell[hdr+2]);276 277  freeTestPage(&tp);278}279 280/* Test 4: intkey leaf with nZero fills zero bytes after nData */281void test_fillInCell_intkey_with_zero_fill(void){282  TestPage tp;283  initTestPage(&tp, 1);284 285  unsigned char cell[128];286  memset(cell, 0xBB, sizeof(cell));287  int cellSize = -1;288 289  /* nData=2 ("hi"), nZero=3 => payload 5 bytes total */290  BtreePayload x;291  memset(&x, 0, sizeof(x));292  x.pData = (void*)"hi";293  x.nData = 2;294  x.nZero = 3;295  x.nKey = 42;296 297  int rc = test_fillInCell(tp.pPage, cell, &x, &cellSize);298  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);299 300  int hdr = 0;301  u8 expect_hdr[16];302  hdr += writeVarint32(expect_hdr+hdr, 5);303  hdr += writeVarint64(expect_hdr+hdr, 42);304  int total = hdr + 5;305  if( total<4 ) total = 4;306 307  TEST_ASSERT_EQUAL_INT(total, cellSize);308  TEST_ASSERT_EQUAL_UINT8_ARRAY(expect_hdr, cell, hdr);309  /* "hi" then three zeros */310  TEST_ASSERT_EQUAL_UINT8('h', cell[hdr+0]);311  TEST_ASSERT_EQUAL_UINT8('i', cell[hdr+1]);312  TEST_ASSERT_EQUAL_UINT8(0x00, cell[hdr+2]);313  TEST_ASSERT_EQUAL_UINT8(0x00, cell[hdr+3]);314  TEST_ASSERT_EQUAL_UINT8(0x00, cell[hdr+4]);315 316  freeTestPage(&tp);317}318 319int main(void){320  UNITY_BEGIN();321  RUN_TEST(test_fillInCell_intkey_basic);322  RUN_TEST(test_fillInCell_intkey_min4);323  RUN_TEST(test_fillInCell_index_basic);324  RUN_TEST(test_fillInCell_intkey_with_zero_fill);325  return UNITY_END();326}