Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
tests_btree_sqlite3BtreeCount.c201 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/* Utility: execute SQL and assert success */8static void execSQL(sqlite3 *db, const char *zSql){9  char *zErr = 0;10  int rc = sqlite3_exec(db, zSql, 0, 0, &zErr);11  if( rc!=SQLITE_OK ){12    /* Print error to help debugging */13    if( zErr ){14      fprintf(stderr, "SQL error: %s\n", zErr);15    }16  }17  TEST_ASSERT_EQUAL_INT_MESSAGE(SQLITE_OK, rc, zErr ? zErr : "exec failed");18  sqlite3_free(zErr);19}20 21/* Utility: open a read cursor for a table by name in "main" schema */22static int openReadCursorForTable(23  sqlite3 *db,24  const char *zTabName,25  Btree **ppBtree,26  BtCursor **ppCur,27  Pgno *pRoot28){29  TEST_ASSERT_NOT_NULL(db);30  TEST_ASSERT_NOT_NULL(ppBtree);31  TEST_ASSERT_NOT_NULL(ppCur);32  TEST_ASSERT_NOT_NULL(pRoot);33 34  /* Find the table root page (tnum) via internal schema */35  Table *pTab = sqlite3FindTable(db, zTabName, "main");36  TEST_ASSERT_NOT_NULL_MESSAGE(pTab, "Table not found in schema");37  *pRoot = (Pgno)pTab->tnum;38 39  /* Get the Btree for "main" */40  *ppBtree = db->aDb[0].pBt;41  TEST_ASSERT_NOT_NULL_MESSAGE(*ppBtree, "Main Btree is NULL");42 43  /* Begin a read transaction */44  int rc = sqlite3BtreeBeginTrans(*ppBtree, 0, 0);45  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);46 47  /* Allocate and open a cursor */48  int nSize = sqlite3BtreeCursorSize();49  BtCursor *pCur = (BtCursor*)sqlite3_malloc(nSize);50  TEST_ASSERT_NOT_NULL_MESSAGE(pCur, "malloc BtCursor failed");51  sqlite3BtreeCursorZero(pCur);52  rc = sqlite3BtreeCursor(*ppBtree, *pRoot, 0, 0, pCur);53  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);54 55  *ppCur = pCur;56  return SQLITE_OK;57}58 59/* Utility: close and free BtCursor */60static void closeAndFreeCursor(BtCursor *pCur){61  if( pCur ){62    sqlite3BtreeCloseCursor(pCur);63    sqlite3_free(pCur);64  }65}66 67void setUp(void){68  /* nothing */69}70void tearDown(void){71  /* nothing */72}73 74/* Test 1: Empty table should count 0 entries */75void test_sqlite3BtreeCount_empty_table(void){76  sqlite3 *db = 0;77  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));78 79  execSQL(db, "CREATE TABLE t_empty(x)");80 81  Btree *pBt = 0;82  BtCursor *pCur = 0;83  Pgno root = 0;84  TEST_ASSERT_EQUAL_INT(SQLITE_OK,85    openReadCursorForTable(db, "t_empty", &pBt, &pCur, &root)86  );87 88  i64 n = -1;89  int rc = sqlite3BtreeCount(db, pCur, &n);90  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);91  TEST_ASSERT_EQUAL_INT64(0, n);92 93  closeAndFreeCursor(pCur);94  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));95}96 97/* Test 2: Small table count */98void test_sqlite3BtreeCount_small_table(void){99  sqlite3 *db = 0;100  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));101 102  execSQL(db, "CREATE TABLE t_small(a)");103  /* Insert 10 rows */104  for(int i=0;i<10;i++){105    char sql[64];106    sqlite3_snprintf(sizeof(sql), sql, "INSERT INTO t_small VALUES(%d);", i);107    execSQL(db, sql);108  }109 110  Btree *pBt = 0;111  BtCursor *pCur = 0;112  Pgno root = 0;113  TEST_ASSERT_EQUAL_INT(SQLITE_OK,114    openReadCursorForTable(db, "t_small", &pBt, &pCur, &root)115  );116 117  i64 n = -1;118  int rc = sqlite3BtreeCount(db, pCur, &n);119  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);120  TEST_ASSERT_EQUAL_INT64(10, n);121 122  closeAndFreeCursor(pCur);123  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));124}125 126/* Test 3: Large table to force multiple pages */127void test_sqlite3BtreeCount_large_table_multi_page(void){128  sqlite3 *db = 0;129  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));130 131  execSQL(db, "CREATE TABLE t_big(a)");132  /* Insert 2000 rows - enough to span several pages in most default builds */133  const int N = 2000;134  execSQL(db, "BEGIN");135  for(int i=0;i<N;i++){136    char sql[64];137    sqlite3_snprintf(sizeof(sql), sql, "INSERT INTO t_big VALUES(%d);", i);138    execSQL(db, sql);139  }140  execSQL(db, "COMMIT");141 142  Btree *pBt = 0;143  BtCursor *pCur = 0;144  Pgno root = 0;145  TEST_ASSERT_EQUAL_INT(SQLITE_OK,146    openReadCursorForTable(db, "t_big", &pBt, &pCur, &root)147  );148 149  i64 n = -1;150  int rc = sqlite3BtreeCount(db, pCur, &n);151  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);152  TEST_ASSERT_EQUAL_INT64(N, n);153 154  closeAndFreeCursor(pCur);155  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));156}157 158/* Test 4: Interrupt flag set causes traversal loop to skip; expect count 0 */159void test_sqlite3BtreeCount_interrupted_returns_zero(void){160  sqlite3 *db = 0;161  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_open(":memory:", &db));162 163  execSQL(db, "CREATE TABLE t_int(a)");164  /* Insert some rows */165  for(int i=0;i<50;i++){166    char sql[64];167    sqlite3_snprintf(sizeof(sql), sql, "INSERT INTO t_int VALUES(%d);", i);168    execSQL(db, sql);169  }170 171  Btree *pBt = 0;172  BtCursor *pCur = 0;173  Pgno root = 0;174  TEST_ASSERT_EQUAL_INT(SQLITE_OK,175    openReadCursorForTable(db, "t_int", &pBt, &pCur, &root)176  );177 178  /* Set the interrupt flag before calling count */179  db->u1.isInterrupted = 1;180 181  i64 n = -1;182  int rc = sqlite3BtreeCount(db, pCur, &n);183  /* Function still returns SQLITE_OK but should have skipped traversal */184  TEST_ASSERT_EQUAL_INT(SQLITE_OK, rc);185  TEST_ASSERT_EQUAL_INT64(0, n);186 187  /* Clear interrupt flag for cleanliness */188  db->u1.isInterrupted = 0;189 190  closeAndFreeCursor(pCur);191  TEST_ASSERT_EQUAL_INT(SQLITE_OK, sqlite3_close(db));192}193 194int main(void){195  UNITY_BEGIN();196  RUN_TEST(test_sqlite3BtreeCount_empty_table);197  RUN_TEST(test_sqlite3BtreeCount_small_table);198  RUN_TEST(test_sqlite3BtreeCount_large_table_multi_page);199  RUN_TEST(test_sqlite3BtreeCount_interrupted_returns_zero);200  return UNITY_END();201}