diff --git a/core/translate/optimizer/mod.rs b/core/translate/optimizer/mod.rs index edbd35ec9..627017b27 100644 --- a/core/translate/optimizer/mod.rs +++ b/core/translate/optimizer/mod.rs @@ -707,11 +707,7 @@ impl Optimizable for ast::Expr { func.is_deterministic() && args.iter().all(|arg| arg.is_constant(resolver)) } Expr::FunctionCallStar { .. } => false, - Expr::Id(id) => { - // If we got here with an id, this has to be double-quotes identifier - assert!(id.quoted_with('"')); - true - } + Expr::Id(_) => true, Expr::Column { .. } => false, Expr::RowId { .. } => false, Expr::InList { lhs, rhs, .. } => { diff --git a/testing/cli_tests/cli_test_cases.py b/testing/cli_tests/cli_test_cases.py index c649c7474..fa07285d4 100755 --- a/testing/cli_tests/cli_test_cases.py +++ b/testing/cli_tests/cli_test_cases.py @@ -355,6 +355,20 @@ def test_copy_memory_db_to_file(): sqlite.quit() +def test_parse_error(): + testpath = "testing/memory.db" + if Path(testpath).exists(): + os.unlink(Path(testpath)) + time.sleep(0.2) # make sure closed + + turso = TestTursoShell(init_commands="") + turso.run_test_fn( + "select * from sqlite_schema limit asdf;", + lambda res: "Parse error: " in res, + "Try to LIMIT using an identifier should trigger a Parse error", + ) + + def main(): console.info("Running all turso CLI tests...") test_basic_queries() @@ -378,6 +392,7 @@ def main(): test_uri_readonly() test_copy_db_file() test_copy_memory_db_to_file() + test_parse_error() console.info("All tests have passed") diff --git a/testing/cli_tests/extensions.py b/testing/cli_tests/extensions.py index fb1279d45..5f90014a9 100755 --- a/testing/cli_tests/extensions.py +++ b/testing/cli_tests/extensions.py @@ -31,31 +31,31 @@ def validate_string_uuid(res): def test_uuid(): - limbo = TestTursoShell() + turso = TestTursoShell() specific_time = "01945ca0-3189-76c0-9a8f-caf310fc8b8e" # these are built into the binary, so we just test they work - limbo.run_test_fn( + turso.run_test_fn( "SELECT hex(uuid4());", lambda res: int(res, 16) is not None, "uuid functions are registered properly with ext loaded", ) - limbo.run_test_fn("SELECT uuid4_str();", lambda res: len(res) == 36) - limbo.run_test_fn("SELECT hex(uuid7());", lambda res: int(res, 16) is not None) - limbo.run_test_fn("SELECT uuid7_timestamp_ms(uuid7()) / 1000;", lambda res: res.isdigit()) - limbo.run_test_fn("SELECT uuid7_str();", validate_string_uuid) - limbo.run_test_fn("SELECT uuid_str(uuid7());", validate_string_uuid) - limbo.run_test_fn("SELECT hex(uuid_blob(uuid7_str()));", lambda res: int(res, 16) is not None) - limbo.run_test_fn("SELECT uuid_str(uuid_blob(uuid7_str()));", validate_string_uuid) - limbo.run_test_fn( + turso.run_test_fn("SELECT uuid4_str();", lambda res: len(res) == 36) + turso.run_test_fn("SELECT hex(uuid7());", lambda res: int(res, 16) is not None) + turso.run_test_fn("SELECT uuid7_timestamp_ms(uuid7()) / 1000;", lambda res: res.isdigit()) + turso.run_test_fn("SELECT uuid7_str();", validate_string_uuid) + turso.run_test_fn("SELECT uuid_str(uuid7());", validate_string_uuid) + turso.run_test_fn("SELECT hex(uuid_blob(uuid7_str()));", lambda res: int(res, 16) is not None) + turso.run_test_fn("SELECT uuid_str(uuid_blob(uuid7_str()));", validate_string_uuid) + turso.run_test_fn( f"SELECT uuid7_timestamp_ms('{specific_time}') / 1000;", lambda res: res == "1736720789", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT gen_random_uuid();", validate_string_uuid, "scalar alias's are registered properly", ) - limbo.quit() + turso.quit() def true(res): @@ -71,51 +71,51 @@ def null(res): def test_regexp(): - limbo = TestTursoShell(test_data) + turso = TestTursoShell(test_data) extension_path = "./target/debug/liblimbo_regexp" # before extension loads, assert no function - limbo.run_test_fn( + turso.run_test_fn( "SELECT regexp('a.c', 'abc');", lambda res: "Parse error: no such function" in res, ) - limbo.run_test_fn(f".load {extension_path}", null) + turso.run_test_fn(f".load {extension_path}", null) console.info(f"Extension {extension_path} loaded successfully.") - limbo.run_test_fn("SELECT regexp('a.c', 'abc');", true) - limbo.run_test_fn("SELECT regexp('a.c', 'ac');", false) - limbo.run_test_fn("SELECT regexp('[0-9]+', 'the year is 2021');", true) - limbo.run_test_fn("SELECT regexp('[0-9]+', 'the year is unknow');", false) - limbo.run_test_fn("SELECT regexp_like('the year is 2021', '[0-9]+');", true) - limbo.run_test_fn("SELECT regexp_like('the year is unknow', '[0-9]+');", false) - limbo.run_test_fn( + turso.run_test_fn("SELECT regexp('a.c', 'abc');", true) + turso.run_test_fn("SELECT regexp('a.c', 'ac');", false) + turso.run_test_fn("SELECT regexp('[0-9]+', 'the year is 2021');", true) + turso.run_test_fn("SELECT regexp('[0-9]+', 'the year is unknow');", false) + turso.run_test_fn("SELECT regexp_like('the year is 2021', '[0-9]+');", true) + turso.run_test_fn("SELECT regexp_like('the year is unknow', '[0-9]+');", false) + turso.run_test_fn( "SELECT regexp_substr('the year is 2021', '[0-9]+') = '2021';", true, ) - limbo.run_test_fn("SELECT regexp_substr('the year is unknow', '[0-9]+');", null) - limbo.run_test_fn( + turso.run_test_fn("SELECT regexp_substr('the year is unknow', '[0-9]+');", null) + turso.run_test_fn( "select regexp_replace('the year is 2021', '[0-9]+', '2050') = 'the year is 2050';", true, ) - limbo.run_test_fn( + turso.run_test_fn( "select regexp_replace('the year is 2021', '2k21', '2050') = 'the year is 2021';", true, ) - limbo.run_test_fn( + turso.run_test_fn( "select regexp_replace('the year is 2021', '([0-9]+)', '$1 or 2050') = 'the year is 2021 or 2050';", true, ) - limbo.run_test_fn( + turso.run_test_fn( "select regexp_capture('the year is 2021', '([0-9]+)') = '2021';", true, ) - limbo.run_test_fn( + turso.run_test_fn( "select regexp_capture('abc 123 def', '([a-z]+) ([0-9]+) ([a-z]+)', 2) = '123';", true, ) - limbo.run_test_fn( + turso.run_test_fn( "select regexp_capture('no digits here', '([0-9]+)');", null, ) - limbo.quit() + turso.quit() def validate_median(res): @@ -139,82 +139,82 @@ def validate_percentile_disc(res): def test_aggregates(): - limbo = TestTursoShell(init_commands=test_data) + turso = TestTursoShell(init_commands=test_data) extension_path = "./target/debug/liblimbo_percentile" # assert no function before extension loads - limbo.run_test_fn( + turso.run_test_fn( "SELECT median(1);", lambda res: "error: no such function: " in res, "median agg function returns null when ext not loaded", ) - limbo.execute_dot(f".load {extension_path}") - limbo.run_test_fn( + turso.execute_dot(f".load {extension_path}") + turso.run_test_fn( "select median(value) from numbers;", validate_median, "median agg function works", ) - limbo.run_test_fn( + turso.run_test_fn( "select CASE WHEN median(value) > 0 THEN median(value) ELSE 0 END from numbers;", validate_median, "median agg function wrapped in expression works", ) - limbo.execute_dot("INSERT INTO numbers (value) VALUES (8.0);\n") - limbo.run_test_fn( + turso.execute_dot("INSERT INTO numbers (value) VALUES (8.0);\n") + turso.run_test_fn( "select median(value) from numbers;", validate_median_odd, "median agg function works with odd number of elements", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile(value, percent) from test;", validate_percentile1, "test aggregate percentile function with 2 arguments works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile(value, 55) from test;", validate_percentile2, "test aggregate percentile function with 1 argument works", ) - limbo.run_test_fn("SELECT percentile_cont(value, 0.25) from test;", validate_percentile1) - limbo.run_test_fn("SELECT percentile_disc(value, 0.55) from test;", validate_percentile_disc) - limbo.quit() + turso.run_test_fn("SELECT percentile_cont(value, 0.25) from test;", validate_percentile1) + turso.run_test_fn("SELECT percentile_disc(value, 0.55) from test;", validate_percentile_disc) + turso.quit() def test_grouped_aggregates(): - limbo = TestTursoShell(init_commands=test_data) + turso = TestTursoShell(init_commands=test_data) extension_path = "./target/debug/liblimbo_percentile" - limbo.execute_dot(f".load {extension_path}") + turso.execute_dot(f".load {extension_path}") - limbo.run_test_fn( + turso.run_test_fn( "SELECT median(value) FROM numbers GROUP BY category;", lambda res: "2.0\n5.5" == res, "median aggregate function works", ) - limbo.run_test_fn( + turso.run_test_fn( "select CASE WHEN median(value) > 0 THEN median(value) ELSE 0 END from numbers GROUP BY category;", lambda res: "2.0\n5.5" == res, "median aggregate function wrapped in expression works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile(value, percent) FROM test GROUP BY category;", lambda res: "12.5\n30.0\n45.0\n70.0" == res, "grouped aggregate percentile function with 2 arguments works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile(value, 55) FROM test GROUP BY category;", lambda res: "15.5\n30.0\n51.0\n70.0" == res, "grouped aggregate percentile function with 1 argument works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile_cont(value, 0.25) FROM test GROUP BY category;", lambda res: "12.5\n30.0\n45.0\n70.0" == res, "grouped aggregate percentile_cont function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT percentile_disc(value, 0.55) FROM test GROUP BY category;", lambda res: "10.0\n30.0\n50.0\n70.0" == res, "grouped aggregate percentile_disc function works", ) - limbo.quit() + turso.quit() # Encoders and decoders @@ -259,43 +259,43 @@ def validate_base64_decode(a): def test_crypto(): - limbo = TestTursoShell() + turso = TestTursoShell() extension_path = "./target/debug/liblimbo_crypto" # assert no function before extension loads - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_blake('a');", lambda res: "Parse error" in res, "crypto_blake3 returns null when ext not loaded", ) - limbo.execute_dot(f".load {extension_path}") + turso.execute_dot(f".load {extension_path}") # Hashing and Decode - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_blake3('abc'), 'hex');", lambda res: res == "6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85", "blake3 should encrypt correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_md5('abc'), 'hex');", lambda res: res == "900150983cd24fb0d6963f7d28e17f72", "md5 should encrypt correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_sha1('abc'), 'hex');", lambda res: res == "a9993e364706816aba3e25717850c26c9cd0d89d", "sha1 should encrypt correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_sha256('abc'), 'hex');", lambda a: a == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "sha256 should encrypt correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_sha384('abc'), 'hex');", lambda a: a == "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "sha384 should encrypt correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode(crypto_sha512('abc'), 'hex');", lambda a: a == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", # noqa: E501 @@ -303,67 +303,67 @@ def test_crypto(): ) # Encoding and Decoding - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode('hello', 'base32');", validate_base32_encode, "base32 should encode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_decode('NBSWY3DP', 'base32');", validate_base32_decode, "base32 should decode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode('hello', 'base64');", validate_base64_encode, "base64 should encode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_decode('aGVsbG8=', 'base64');", validate_base64_decode, "base64 should decode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode('hello', 'base85');", validate_base85_encode, "base85 should encode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_decode('BOu!rDZ', 'base85');", validate_base85_decode, "base85 should decode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode('hello', 'hex');", validate_hex_encode, "hex should encode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_decode('68656c6c6f', 'hex');", validate_hex_decode, "hex should decode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_encode('/hello?text=(ಠ_ಠ)', 'url');", validate_url_encode, "url should encode correctly", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT crypto_decode('%2Fhello%3Ftext%3D%28%E0%B2%A0_%E0%B2%A0%29', 'url');", validate_url_decode, "url should decode correctly", ) - limbo.quit() + turso.quit() def test_series(): console.info("Running test_series for Limbo") - limbo = TestTursoShell() - _test_series(limbo) + turso = TestTursoShell() + _test_series(turso) console.info("Running test_series for SQLite") - limbo = TestTursoShell(exec_name="sqlite3") - _test_series(limbo) + turso = TestTursoShell(exec_name="sqlite3") + _test_series(turso) def _test_series(limbo: TestTursoShell): @@ -399,78 +399,78 @@ def test_kv(): def _test_kv(exec_name, ext_path): console.info(f"Running test_kv for {ext_path} in {exec_name}") - limbo = TestTursoShell( + turso = TestTursoShell( exec_name=exec_name, ) # first, create a normal table to ensure no issues - limbo.execute_dot("CREATE TABLE other (a,b,c);") - limbo.execute_dot("INSERT INTO other values (23,32,23);") - limbo.run_test_fn( + turso.execute_dot("CREATE TABLE other (a,b,c);") + turso.execute_dot("INSERT INTO other values (23,32,23);") + turso.run_test_fn( "create virtual table t using kv_store;", lambda res: "no such module: kv_store" in res, ) - limbo.execute_dot(f".load {ext_path}") - limbo.execute_dot( + turso.execute_dot(f".load {ext_path}") + turso.execute_dot( "create virtual table t using kv_store;", ) - limbo.run_test_fn(".schema", lambda res: "CREATE VIRTUAL TABLE t" in res) - limbo.run_test_fn( + turso.run_test_fn(".schema", lambda res: "CREATE VIRTUAL TABLE t" in res) + turso.run_test_fn( "insert into t values ('hello', 'world');", null, "can insert into kv_store vtable", ) - limbo.run_test_fn( + turso.run_test_fn( "select value from t where key = 'hello';", lambda res: "world" == res, "can select from kv_store", ) - limbo.run_test_fn( + turso.run_test_fn( "delete from t where key = 'hello';", null, "can delete from kv_store", ) - limbo.run_test_fn("insert into t values ('other', 'value');", null) - limbo.run_test_fn( + turso.run_test_fn("insert into t values ('other', 'value');", null) + turso.run_test_fn( "select value from t where key = 'hello';", lambda res: "" == res, "proper data is deleted", ) - limbo.run_test_fn( + turso.run_test_fn( "select * from t;", lambda res: "other|value" == res, "can select after deletion", ) - limbo.run_test_fn( + turso.run_test_fn( "delete from t where key = 'other';", null, "can delete from kv_store", ) - limbo.run_test_fn( + turso.run_test_fn( "select * from t;", lambda res: "" == res, "can select empty table without error", ) - limbo.run_test_fn( + turso.run_test_fn( "delete from t;", null, "can delete from empty table without error", ) for i in range(100): - limbo.execute_dot(f"insert into t values ('key{i}', 'val{i}');") - limbo.run_test_fn("select count(*) from t;", lambda res: "100" == res, "can insert 100 rows") - limbo.run_test_fn("update t set value = 'updated' where key = 'key33';", null) - limbo.run_test_fn( + turso.execute_dot(f"insert into t values ('key{i}', 'val{i}');") + turso.run_test_fn("select count(*) from t;", lambda res: "100" == res, "can insert 100 rows") + turso.run_test_fn("update t set value = 'updated' where key = 'key33';", null) + turso.run_test_fn( "select * from t where key = 'key33';", lambda res: res == "key33|updated", "can update single row", ) - limbo.run_test_fn( + turso.run_test_fn( "select COUNT(*) from t where value = 'updated';", lambda res: res == "1", "only updated a single row", ) - limbo.run_test_fn("update t set value = 'updated2';", null) - limbo.run_test_fn( + turso.run_test_fn("update t set value = 'updated2';", null) + turso.run_test_fn( "select COUNT(*) from t where value = 'updated2';", lambda res: res == "100", "can update all rows", @@ -478,229 +478,245 @@ def _test_kv(exec_name, ext_path): if exec_name is None: # Test only on Limbo, since SQLite supports the DELETE ... LIMIT syntax only when compiled # with the SQLITE_ENABLE_UPDATE_DELETE_LIMIT option: https://www.sqlite.org/lang_delete.html - limbo.run_test_fn("delete from t limit 96;", null, "can delete 96 rows") - limbo.run_test_fn("select count(*) from t;", lambda res: "4" == res, "four rows remain") - limbo.run_test_fn("update t set key = '100' where 1;", null, "where clause evaluates properly") - limbo.run_test_fn( + turso.run_test_fn("delete from t limit 96;", null, "can delete 96 rows") + turso.run_test_fn("select count(*) from t;", lambda res: "4" == res, "four rows remain") + turso.run_test_fn("update t set key = '100' where 1;", null, "where clause evaluates properly") + turso.run_test_fn( "select * from t where key = '100';", lambda res: res == "100|updated2", "there is only 1 key remaining after setting all keys to same value", ) - limbo.run_test_fn( + turso.run_test_fn( "select * from t a, other b where b.c = 23 and a.key='100';", lambda res: "100|updated2|23|32|23" == res, ) - limbo.quit() + turso.quit() def test_ipaddr(): - limbo = TestTursoShell() + turso = TestTursoShell() ext_path = "./target/debug/liblimbo_ipaddr" - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipfamily('192.168.1.1');", lambda res: "error: no such function: " in res, "ipfamily function returns null when ext not loaded", ) - limbo.execute_dot(f".load {ext_path}") + turso.execute_dot(f".load {ext_path}") - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipfamily('192.168.1.1');", lambda res: "4" == res, "ipfamily function returns 4 for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipfamily('2001:db8::1');", lambda res: "6" == res, "ipfamily function returns 6 for IPv6", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipcontains('192.168.16.0/24', '192.168.16.3');", lambda res: "1" == res, "ipcontains function returns 1 for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipcontains('192.168.1.0/24', '192.168.2.1');", lambda res: "0" == res, "ipcontains function returns 0 for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT iphost('192.168.1.0/24');", lambda res: "192.168.1.0" == res, "iphost function returns the host for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT iphost('2001:db8::1/128');", lambda res: "2001:db8::1" == res, "iphost function returns the host for IPv6", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipmasklen('192.168.1.0/24');", lambda res: "24" == res, "ipmasklen function returns the mask length for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipmasklen('2001:db8::1');", lambda res: "128" == res, "ipmasklen function returns the mask length for IPv6", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipnetwork('192.168.16.12/24');", lambda res: "192.168.16.0/24" == res, "ipnetwork function returns the flattened CIDR for IPv4", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT ipnetwork('2001:db8::1');", lambda res: "2001:db8::1/128" == res, "ipnetwork function returns the network for IPv6", ) - limbo.quit() + turso.quit() + def validate_fuzzy_leven(a): return a == "3" + def validate_fuzzy_damlev1(a): return a == "2" + def validate_fuzzy_damlev2(a): return a == "1" + def validate_fuzzy_editdist1(a): return a == "225" + def validate_fuzzy_editdist2(a): return a == "110" + def validate_fuzzy_jarowin(a): return a == "0.907142857142857" + def validate_fuzzy_osadist(a): return a == "3" + def validate_fuzzy_soundex(a): return a == "A250" + def validate_fuzzy_phonetic(a): return a == "ABACAMA" + def validate_fuzzy_caver(a): return a == "AWSM111111" + def validate_fuzzy_rsoundex(a): return a == "A03080" + def validate_fuzzy_translit1(a): return a == "oh my ?" + def validate_fuzzy_translit2(a): return a == "privet" + def validate_fuzzy_script(a): return a == "160" + def test_fuzzy(): - limbo = TestTursoShell() + turso = TestTursoShell() ext_path = "./target/debug/liblimbo_fuzzy" - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_leven('awesome', 'aewsme');", lambda res: "error: no such function: " in res, "fuzzy levenshtein function returns null when ext not loaded", ) - limbo.execute_dot(f".load {ext_path}") - limbo.run_test_fn( + turso.execute_dot(f".load {ext_path}") + turso.run_test_fn( "SELECT fuzzy_leven('awesome', 'aewsme');", validate_fuzzy_leven, "fuzzy levenshtein function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_damlev('awesome', 'aewsme');", validate_fuzzy_damlev1, "fuzzy damerau levenshtein1 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_damlev('Something', 'Smoething');", validate_fuzzy_damlev2, "fuzzy damerau levenshtein2 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_editdist('abc', 'ca');", validate_fuzzy_editdist1, "fuzzy editdist1 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_editdist('abc', 'acb');", validate_fuzzy_editdist2, "fuzzy editdist2 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_jarowin('awesome', 'aewsme');", validate_fuzzy_jarowin, "fuzzy jarowin function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_osadist('awesome', 'aewsme');", validate_fuzzy_osadist, "fuzzy osadist function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_phonetic('awesome');", validate_fuzzy_phonetic, "fuzzy phonetic function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_caver('awesome');", validate_fuzzy_caver, "fuzzy caver function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_rsoundex('awesome');", validate_fuzzy_rsoundex, "fuzzy rsoundex function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_translit('oh my 😅');", validate_fuzzy_translit1, "fuzzy translit1 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_translit('привет');", validate_fuzzy_translit2, "fuzzy translit2 function works", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT fuzzy_script('داناوانب');", validate_fuzzy_script, "fuzzy script function works", ) + def test_vfs(): - limbo = TestTursoShell() + turso = TestTursoShell() ext_path = "target/debug/libturso_ext_tests" - limbo.run_test_fn(".vfslist", lambda x: "testvfs" not in x, "testvfs not loaded") - limbo.execute_dot(f".load {ext_path}") - limbo.run_test_fn(".vfslist", lambda res: "testvfs" in res, "testvfs extension loaded") - limbo.execute_dot(".open testing/vfs.db testvfs") - limbo.execute_dot("create table test (id integer primary key, value float);") - limbo.execute_dot("create table vfs (id integer primary key, value blob);") + turso.run_test_fn(".vfslist", lambda x: "testvfs" not in x, "testvfs not loaded") + turso.execute_dot(f".load {ext_path}") + turso.run_test_fn(".vfslist", lambda res: "testvfs" in res, "testvfs extension loaded") + turso.execute_dot(".open testing/vfs.db testvfs") + turso.execute_dot("create table test (id integer primary key, value float);") + turso.execute_dot("create table vfs (id integer primary key, value blob);") for i in range(50): - limbo.execute_dot("insert into test (value) values (randomblob(32*1024));") - limbo.execute_dot(f"insert into vfs (value) values ({i});") - limbo.run_test_fn( + turso.execute_dot("insert into test (value) values (randomblob(32*1024));") + turso.execute_dot(f"insert into vfs (value) values ({i});") + turso.run_test_fn( "SELECT count(*) FROM test;", lambda res: res == "50", "Tested large write to testfs", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT count(*) FROM vfs;", lambda res: res == "50", "Tested large write to testfs", ) console.info("Tested large write to testfs") - limbo.quit() + turso.quit() def test_sqlite_vfs_compat(): @@ -735,81 +751,81 @@ def test_sqlite_vfs_compat(): def test_csv(): # open new empty connection explicitly to test whether we can load an extension # with brand new connection/uninitialized database. - limbo = TestTursoShell(init_commands="") - test_module_list(limbo, "target/debug/liblimbo_csv", "csv") + turso = TestTursoShell(init_commands="") + test_module_list(turso, "target/debug/liblimbo_csv", "csv") - limbo.run_test_fn( + turso.run_test_fn( "CREATE VIRTUAL TABLE temp.csv USING csv(filename=./testing/test_files/test.csv);", null, "Create virtual table from CSV file", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM temp.csv;", lambda res: res == "1|2.0|String'1\n3|4.0|String2", "Read all rows from CSV table", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM temp.csv WHERE c2 = 'String2';", lambda res: res == "3|4.0|String2", "Filter rows with WHERE clause", ) - limbo.run_test_fn( + turso.run_test_fn( "INSERT INTO temp.csv VALUES (5, 6.0, 'String3');", lambda res: "Table is read-only" in res, "INSERT into CSV table should fail", ) - limbo.run_test_fn( + turso.run_test_fn( "UPDATE temp.csv SET c0 = 10 WHERE c1 = '2.0';", lambda res: "is read-only" in res, "UPDATE on CSV table should fail", ) - limbo.run_test_fn( + turso.run_test_fn( "DELETE FROM temp.csv WHERE c1 = '2.0';", lambda res: "is read-only" in res, "DELETE on CSV table should fail", ) - limbo.run_test_fn("DROP TABLE temp.csv;", null, "Drop CSV table") - limbo.run_test_fn( + turso.run_test_fn("DROP TABLE temp.csv;", null, "Drop CSV table") + turso.run_test_fn( "SELECT * FROM temp.csv;", lambda res: "Parse error: no such table: csv" in res, "Query dropped CSV table should fail", ) - limbo.run_test_fn( + turso.run_test_fn( "create virtual table t1 using csv(data='1'\\'2');", lambda res: "unrecognized token at" in res, "Create CSV table with malformed escape sequence", ) - limbo.run_test_fn( + turso.run_test_fn( "create virtual table t1 using csv(data=\"12');", lambda res: "non-terminated literal at" in res, "Create CSV table with unterminated quoted string", ) - limbo.run_debug("create virtual table t1 using csv(data='');") - limbo.run_test_fn( + turso.run_debug("create virtual table t1 using csv(data='');") + turso.run_test_fn( "SELECT c0 FROM t1;", lambda res: res == "", "Empty CSV table without a header should have one column: 'c0'", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT c1 FROM t1;", lambda res: "Parse error: no such column: c1" in res, "Empty CSV table without header should not have columns other than 'c0'", ) - limbo.run_debug("create virtual table t2 using csv(data='', header=true);") - limbo.run_test_fn( + turso.run_debug("create virtual table t2 using csv(data='', header=true);") + turso.run_test_fn( 'SELECT "(NULL)" FROM t2;', lambda res: res == "", "Empty CSV table with header should have one column named '(NULL)'", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT c0 FROM t2;", lambda res: "Parse error: no such column: c0" in res, "Empty CSV table with header should not have columns other than '(NULL)'", ) - limbo.quit() + turso.quit() def cleanup(): @@ -821,45 +837,45 @@ def cleanup(): def test_tablestats(): ext_path = "target/debug/libturso_ext_tests" - limbo = TestTursoShell(use_testing_db=True) - test_module_list(limbo, ext_path=ext_path, module_name="tablestats") - limbo.execute_dot("CREATE TABLE people(id INTEGER PRIMARY KEY, name TEXT);") - limbo.execute_dot("INSERT INTO people(name) VALUES ('Ada'), ('Grace'), ('Linus');") + turso = TestTursoShell(use_testing_db=True) + test_module_list(turso, ext_path=ext_path, module_name="tablestats") + turso.execute_dot("CREATE TABLE people(id INTEGER PRIMARY KEY, name TEXT);") + turso.execute_dot("INSERT INTO people(name) VALUES ('Ada'), ('Grace'), ('Linus');") - limbo.execute_dot("CREATE TABLE logs(ts INT, msg TEXT);") - limbo.execute_dot("INSERT INTO logs VALUES (1,'boot ok');") + turso.execute_dot("CREATE TABLE logs(ts INT, msg TEXT);") + turso.execute_dot("INSERT INTO logs VALUES (1,'boot ok');") # verify counts - limbo.run_test_fn( + turso.run_test_fn( "SELECT COUNT(*) FROM people;", lambda res: res == "3", "three people rowsverify user count", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT COUNT(*) FROM logs;", lambda res: res == "1", "one logs rowverify logs count", ) - limbo.execute_dot("CREATE VIRTUAL TABLE stats USING tablestats;") + turso.execute_dot("CREATE VIRTUAL TABLE stats USING tablestats;") def _split(res): return [ln.strip() for ln in res.splitlines() if ln.strip()] - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM stats ORDER BY name;", lambda res: sorted(_split(res)) == sorted(["logs|1", "people|3", "products|11", "users|10000"]), "stats shows correct initial counts (and skips itself)", ) - limbo.execute_dot("INSERT INTO logs VALUES (2,'panic'), (3,'recovery');") - limbo.execute_dot("DELETE FROM people WHERE name='Linus';") + turso.execute_dot("INSERT INTO logs VALUES (2,'panic'), (3,'recovery');") + turso.execute_dot("DELETE FROM people WHERE name='Linus';") - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM stats WHERE name='logs';", lambda res: res == "logs|3", "row‑count grows after INSERT", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM stats WHERE name='people';", lambda res: res == "people|2", "row‑count shrinks after DELETE", @@ -869,7 +885,7 @@ def test_tablestats(): # the test extension is also doing a testing insert on every query # as part of its own testing, so we cannot assert 'products|11' # we need to add 3 for the 3 queries we did above. - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM stats WHERE name='products';", lambda x: x == "products|14", "products table reflects changes", @@ -877,32 +893,32 @@ def test_tablestats(): # an insert to products with (name,price) ('xConnect', 42) # has happened on each query (4 so far) in the testing extension. # so at this point the sum should be 168 - limbo.run_test_fn( + turso.run_test_fn( "SELECT sum(price) FROM products WHERE name = 'xConnect';", lambda x: x == "168.0", "price sum for 'xConnect' inserts happenning in the testing extension", ) - limbo.run_test_fn( + turso.run_test_fn( "SELECT * FROM stats WHERE name='users';", lambda x: x == "users|10000", "users table unchanged", ) - limbo.execute_dot("CREATE TABLE misc(x);") - limbo.run_test_fn( + turso.execute_dot("CREATE TABLE misc(x);") + turso.run_test_fn( "SELECT * FROM stats WHERE name='misc';", lambda res: res == "misc|0", "newly‑created table shows up with zero rows", ) - limbo.execute_dot("DROP TABLE logs;") - limbo.run_test_fn( + turso.execute_dot("DROP TABLE logs;") + turso.run_test_fn( "SELECT name FROM stats WHERE name='logs';", lambda res: res == "", "dropped table disappears from stats", ) - limbo.quit() + turso.quit() def test_module_list(turso_shell, ext_path, module_name): diff --git a/testing/cli_tests/memory.py b/testing/cli_tests/memory.py index efc3e402a..ad4a6ac73 100755 --- a/testing/cli_tests/memory.py +++ b/testing/cli_tests/memory.py @@ -12,7 +12,7 @@ def validate_with_expected(result: str, expected: str): def stub_memory_test( - limbo: TestTursoShell, + turso: TestTursoShell, name: str, blob_size: int = 1024**2, vals: int = 100, @@ -50,10 +50,10 @@ def stub_memory_test( big_stmt = "".join(big_stmt) expected = "\n".join(expected) - limbo.run_test_fn(big_stmt, lambda res: validate_with_expected(res, expected), name) + turso.run_test_fn(big_stmt, lambda res: validate_with_expected(res, expected), name) -# TODO no delete tests for now because of limbo outputs some debug information on delete +# TODO no delete tests for now because of turso outputs some debug information on delete def memory_tests() -> list[dict]: tests = [] @@ -106,8 +106,8 @@ def main(): # TODO see how to parallelize this loop with different subprocesses for test in tests: try: - with TestTursoShell("") as limbo: - stub_memory_test(limbo, **test) + with TestTursoShell("") as turso: + stub_memory_test(turso, **test) except Exception as e: console.error(f"Test FAILED: {e}") exit(1) diff --git a/testing/default_value.test b/testing/default_value.test index 8215527e1..b4fc9c9aa 100644 --- a/testing/default_value.test +++ b/testing/default_value.test @@ -39,5 +39,8 @@ do_execsql_test_on_specific_db {:memory:} default-value-function { SELECT y FROM t7 WHERE x = 1; } {5} - - +do_execsql_test_on_specific_db {:memory:} default-value-identifier { + CREATE TABLE t7 (x INTEGER PRIMARY KEY, y DEFAULT asdf); + INSERT INTO t7 (x) VALUES (1); + SELECT y FROM t7 WHERE x = 1; +} {asdf} diff --git a/testing/select.test b/testing/select.test index bfa214e81..cfa12ce17 100755 --- a/testing/select.test +++ b/testing/select.test @@ -261,15 +261,15 @@ do_execsql_test select-invalid-numeric-text { do_execsql_test_on_specific_db {:memory:} select-union-all-1 { CREATE TABLE t1 (x INTEGER); - CREATE TABLE t2 (x INTEGER); + CREATE TABLE t2 (x INTEGER); CREATE TABLE t3 (x INTEGER); - + INSERT INTO t1 VALUES(1),(2),(3); INSERT INTO t2 VALUES(4),(5),(6); INSERT INTO t3 VALUES(7),(8),(9); - + SELECT x FROM t1 - UNION ALL + UNION ALL SELECT x FROM t2 UNION ALL SELECT x FROM t3; @@ -287,14 +287,14 @@ do_execsql_test_on_specific_db {:memory:} select-union-all-with-filters { CREATE TABLE t4 (x INTEGER); CREATE TABLE t5 (x INTEGER); CREATE TABLE t6 (x INTEGER); - + INSERT INTO t4 VALUES(1),(2),(3),(4); INSERT INTO t5 VALUES(5),(6),(7),(8); INSERT INTO t6 VALUES(9),(10),(11),(12); SELECT x FROM t4 WHERE x > 2 UNION ALL - SELECT x FROM t5 WHERE x < 7 + SELECT x FROM t5 WHERE x < 7 UNION ALL SELECT x FROM t6 WHERE x = 10; } {3 @@ -786,4 +786,4 @@ do_execsql_test_on_specific_db {:memory:} rowid-references { AND "oid" = 2 AND `oid` = 2 AND [oid] = 2; -} {2|2|2|2|2|2|2|2|2|2|2|2} \ No newline at end of file +} {2|2|2|2|2|2|2|2|2|2|2|2}