import vibesql
def test_connection():
db = vibesql.connect()
assert db is not None
db.close()
def test_cursor_creation():
db = vibesql.connect()
cursor = db.cursor()
assert cursor is not None
cursor.close()
db.close()
def test_create_table():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.close()
db.close()
def test_insert_select():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 1
assert rows[0] == (1, 'Alice')
cursor.close()
db.close()
def test_multiple_inserts():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
cursor.execute("INSERT INTO users VALUES (3, 'Charlie')")
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 3
assert rows[0] == (1, 'Alice')
assert rows[1] == (2, 'Bob')
assert rows[2] == (3, 'Charlie')
cursor.close()
db.close()
def test_data_types():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE datatypes (i INTEGER, f FLOAT, s VARCHAR(50), b BOOLEAN, n INTEGER)")
cursor.execute("INSERT INTO datatypes VALUES (42, 3.14, 'hello', TRUE, NULL)")
cursor.execute("SELECT * FROM datatypes")
row = cursor.fetchone()
assert row[0] == 42
assert abs(row[1] - 3.14) < 0.01 assert row[2] == 'hello'
assert row[3] == True
assert row[4] is None
cursor.close()
db.close()
def test_fetchone():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE numbers (n INTEGER)")
cursor.execute("INSERT INTO numbers VALUES (1)")
cursor.execute("INSERT INTO numbers VALUES (2)")
cursor.execute("INSERT INTO numbers VALUES (3)")
cursor.execute("SELECT * FROM numbers")
row1 = cursor.fetchone()
assert row1 == (1,)
row2 = cursor.fetchone()
assert row2 == (2,)
row3 = cursor.fetchone()
assert row3 == (3,)
row4 = cursor.fetchone()
assert row4 is None
cursor.close()
db.close()
def test_fetchmany():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE numbers (n INTEGER)")
for i in range(10):
cursor.execute(f"INSERT INTO numbers VALUES ({i})")
cursor.execute("SELECT * FROM numbers")
rows = cursor.fetchmany(3)
assert len(rows) == 3
assert rows[0] == (0,)
assert rows[1] == (1,)
assert rows[2] == (2,)
rows = cursor.fetchmany(5)
assert len(rows) == 5
cursor.close()
db.close()
def test_update():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("UPDATE users SET name = 'Alicia' WHERE id = 1")
cursor.execute("SELECT * FROM users")
row = cursor.fetchone()
assert row == (1, 'Alicia')
cursor.close()
db.close()
def test_delete():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
cursor.execute("DELETE FROM users WHERE id = 1")
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 1
assert rows[0] == (2, 'Bob')
cursor.close()
db.close()
def test_rowcount():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
assert cursor.rowcount == 1
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
assert cursor.rowcount == 1
cursor.execute("SELECT * FROM users")
cursor.fetchall()
assert cursor.rowcount == 2
cursor.close()
db.close()
def test_drop_table():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE temp (id INTEGER)")
cursor.execute("DROP TABLE temp")
cursor.close()
db.close()
def test_multiple_cursors():
db = vibesql.connect()
cursor1 = db.cursor()
cursor2 = db.cursor()
cursor1.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor1.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor2.execute("SELECT * FROM users")
rows = cursor2.fetchall()
assert len(rows) == 1
assert rows[0] == (1, 'Alice')
cursor1.close()
cursor2.close()
db.close()
def test_parameterized_select():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
cursor.execute("INSERT INTO users VALUES (3, 'Charlie')")
cursor.execute("SELECT * FROM users WHERE id = ?", (2,))
rows = cursor.fetchall()
assert len(rows) == 1
assert rows[0] == (2, 'Bob')
cursor.close()
db.close()
def test_parameterized_insert():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (?, ?)", (1, 'Alice'))
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 1
assert rows[0] == (1, 'Alice')
cursor.close()
db.close()
def test_parameterized_update():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
cursor.execute("UPDATE users SET name = ? WHERE id = ?", ('Alicia', 1))
cursor.execute("SELECT * FROM users WHERE id = 1")
row = cursor.fetchone()
assert row == (1, 'Alicia')
cursor.close()
db.close()
def test_parameterized_delete():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("INSERT INTO users VALUES (2, 'Bob')")
cursor.execute("INSERT INTO users VALUES (3, 'Charlie')")
cursor.execute("DELETE FROM users WHERE id = ?", (2,))
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 2
assert rows[0] == (1, 'Alice')
assert rows[1] == (3, 'Charlie')
cursor.close()
db.close()
def test_parameterized_multiple_types():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE data (id INTEGER, value FLOAT, name VARCHAR(50), active BOOLEAN)")
cursor.execute("INSERT INTO data VALUES (?, ?, ?, ?)", (1, 3.14, 'test', True))
cursor.execute("SELECT * FROM data")
row = cursor.fetchone()
assert row[0] == 1
assert abs(row[1] - 3.14) < 0.01
assert row[2] == 'test'
assert row[3] == True
cursor.close()
db.close()
def test_parameterized_null_value():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (?, ?)", (1, None))
cursor.execute("SELECT * FROM users")
row = cursor.fetchone()
assert row[0] == 1
assert row[1] is None
cursor.close()
db.close()
def test_parameterized_string_with_quotes():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (?, ?)", (1, "O'Brien"))
cursor.execute("SELECT * FROM users")
row = cursor.fetchone()
assert row[0] == 1
assert row[1] == "O'Brien"
cursor.close()
db.close()
def test_parameterized_error_count_mismatch():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
try:
cursor.execute("INSERT INTO users VALUES (?, ?)", (1,))
assert False, "Should have raised ProgrammingError"
except vibesql.ProgrammingError as e:
assert "Parameter count mismatch" in str(e)
try:
cursor.execute("INSERT INTO users VALUES (?, ?)", (1, 'Alice', 'Extra'))
assert False, "Should have raised ProgrammingError"
except vibesql.ProgrammingError as e:
assert "Parameter count mismatch" in str(e)
cursor.close()
db.close()
def test_parameterized_error_invalid_type():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
try:
cursor.execute("INSERT INTO users VALUES (?, ?)", (1, {'invalid': 'dict'}))
assert False, "Should have raised ProgrammingError"
except vibesql.ProgrammingError as e:
assert "invalid type" in str(e).lower() or "cannot convert" in str(e).lower()
cursor.close()
db.close()
def test_backward_compatibility_no_params():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, name VARCHAR(50))")
cursor.execute("INSERT INTO users VALUES (1, 'Alice')")
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
assert len(rows) == 1
assert rows[0] == (1, 'Alice')
cursor.close()
db.close()
def test_parameterized_complex_where():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE users (id INTEGER, age INTEGER, active BOOLEAN)")
cursor.execute("INSERT INTO users VALUES (1, 25, TRUE)")
cursor.execute("INSERT INTO users VALUES (2, 30, FALSE)")
cursor.execute("INSERT INTO users VALUES (3, 35, TRUE)")
cursor.execute("INSERT INTO users VALUES (4, 40, TRUE)")
cursor.execute("SELECT * FROM users WHERE age > ? AND active = ?", (28, True))
rows = cursor.fetchall()
assert len(rows) == 2
assert rows[0][0] == 3 assert rows[1][0] == 4
cursor.close()
db.close()
def test_statement_cache_hit():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
cursor.execute("INSERT INTO test VALUES (?, ?)", (1, 100))
hits1, misses1, _ = cursor.cache_stats()
cursor.execute("INSERT INTO test VALUES (?, ?)", (2, 200))
hits2, misses2, _ = cursor.cache_stats()
assert hits2 == hits1 + 1, f"Expected cache hit, got hits={hits2}, misses={misses2}"
assert misses2 == misses1, f"Expected no additional miss, got misses={misses2}"
cursor.close()
db.close()
def test_statement_cache_stats():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
for i in range(10):
cursor.execute("INSERT INTO test VALUES (?, ?)", (i, i * 10))
hits, misses, hit_rate = cursor.cache_stats()
assert misses >= 1, "Expected at least 1 cache miss"
assert hits >= 9, f"Expected at least 9 cache hits, got {hits}"
assert 0 <= hit_rate <= 1, f"Hit rate should be between 0 and 1, got {hit_rate}"
cursor.close()
db.close()
def test_statement_cache_invalidation():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER)")
cursor.execute("INSERT INTO test VALUES (?)", (1,))
cursor.execute("INSERT INTO test VALUES (?)", (2,))
hits1, misses1, _ = cursor.cache_stats()
cursor.execute("DROP TABLE test")
cursor.execute("CREATE TABLE test (id INTEGER)")
cursor.execute("INSERT INTO test VALUES (?)", (3,))
hits2, misses2, _ = cursor.cache_stats()
assert misses2 > misses1, "Expected cache to be cleared after DROP TABLE"
cursor.close()
db.close()
def test_statement_cache_performance():
import time
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
for i in range(100):
cursor.execute("INSERT INTO test VALUES (?, ?)", (i, i * 10))
start_time = time.time()
for i in range(1000):
cursor.execute("UPDATE test SET value = value + 1 WHERE id = ?", (i % 100,))
elapsed = time.time() - start_time
hits, misses, hit_rate = cursor.cache_stats()
assert hit_rate > 0.95, f"Expected >95% cache hit rate, got {hit_rate:.2%}"
print(f" 1000 UPDATEs completed in {elapsed*1000:.2f}ms (cache hit rate: {hit_rate:.2%})")
cursor.close()
db.close()
def test_schema_cache_basic():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
cursor.execute("INSERT INTO test VALUES (1, 100)")
cursor.execute("UPDATE test SET value = 200 WHERE id = 1")
hits1, misses1, _ = cursor.schema_cache_stats()
assert misses1 == 1, f"Expected 1 schema cache miss, got {misses1}"
cursor.execute("UPDATE test SET value = 300 WHERE id = 1")
hits2, misses2, _ = cursor.schema_cache_stats()
assert hits2 == 1, f"Expected 1 schema cache hit, got {hits2}"
assert misses2 == 1, f"Expected still 1 schema cache miss, got {misses2}"
cursor.close()
db.close()
def test_schema_cache_multiple_tables():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE table1 (id INTEGER, value INTEGER)")
cursor.execute("CREATE TABLE table2 (id INTEGER, value INTEGER)")
cursor.execute("UPDATE table1 SET value = 100 WHERE id = 1")
hits1, misses1, _ = cursor.schema_cache_stats()
cursor.execute("UPDATE table2 SET value = 200 WHERE id = 1")
hits2, misses2, _ = cursor.schema_cache_stats()
assert misses2 == misses1 + 1, "Expected miss for second table"
cursor.execute("UPDATE table1 SET value = 101 WHERE id = 1")
hits3, misses3, _ = cursor.schema_cache_stats()
assert hits3 > hits2, "Expected schema cache hit for table1"
cursor.close()
db.close()
def test_schema_cache_invalidation_on_ddl():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
cursor.execute("INSERT INTO test VALUES (1, 100)")
cursor.execute("UPDATE test SET value = 200 WHERE id = 1")
hits1, misses1, _ = cursor.schema_cache_stats()
assert misses1 == 1, "Expected initial schema cache miss"
cursor.execute("DROP TABLE test")
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
cursor.execute("INSERT INTO test VALUES (1, 100)")
cursor.execute("UPDATE test SET value = 300 WHERE id = 1")
hits2, misses2, _ = cursor.schema_cache_stats()
assert misses2 > misses1, "Expected schema cache to be cleared after DDL"
cursor.close()
db.close()
def test_schema_cache_hit_rate():
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
for i in range(100):
cursor.execute("INSERT INTO test VALUES (?, ?)", (i, i * 10))
for i in range(100):
cursor.execute("UPDATE test SET value = value + 1 WHERE id = ?", (i,))
hits, misses, hit_rate = cursor.schema_cache_stats()
assert misses == 1, f"Expected exactly 1 schema cache miss, got {misses}"
assert hits == 99, f"Expected 99 schema cache hits, got {hits}"
assert abs(hit_rate - 0.99) < 0.01, f"Expected 99% hit rate, got {hit_rate:.2%}"
print(f" Schema cache: {hits} hits, {misses} misses, {hit_rate:.2%} hit rate")
cursor.close()
db.close()
def test_schema_cache_performance_improvement():
import time
db = vibesql.connect()
cursor = db.cursor()
cursor.execute("CREATE TABLE test (id INTEGER, value INTEGER)")
for i in range(100):
cursor.execute("INSERT INTO test VALUES (?, ?)", (i, i * 10))
start_time = time.time()
for i in range(1000):
cursor.execute("UPDATE test SET value = value + 1 WHERE id = ?", (i % 100,))
elapsed = time.time() - start_time
hits, misses, hit_rate = cursor.schema_cache_stats()
assert hit_rate > 0.98, f"Expected >98% schema cache hit rate, got {hit_rate:.2%}"
assert misses == 1, f"Expected exactly 1 schema cache miss, got {misses}"
print(f" 1000 UPDATEs with schema cache: {elapsed*1000:.2f}ms (schema hit rate: {hit_rate:.2%})")
cursor.close()
db.close()
if __name__ == "__main__":
test_connection()
test_cursor_creation()
test_create_table()
test_insert_select()
test_multiple_inserts()
test_data_types()
test_fetchone()
test_fetchmany()
test_update()
test_delete()
test_rowcount()
test_drop_table()
test_multiple_cursors()
test_parameterized_select()
test_parameterized_insert()
test_parameterized_update()
test_parameterized_delete()
test_parameterized_multiple_types()
test_parameterized_null_value()
test_parameterized_string_with_quotes()
test_parameterized_error_count_mismatch()
test_parameterized_error_invalid_type()
test_backward_compatibility_no_params()
test_parameterized_complex_where()
test_statement_cache_hit()
test_statement_cache_stats()
test_statement_cache_invalidation()
test_statement_cache_performance()
test_schema_cache_basic()
test_schema_cache_multiple_tables()
test_schema_cache_invalidation_on_ddl()
test_schema_cache_hit_rate()
test_schema_cache_performance_improvement()
print("All tests passed!")