limbo/testing/cli_tests/collate.py
2025-07-02 10:57:46 -04:00

147 lines
5 KiB
Python

#!/usr/bin/env python3
import os
from cli_tests import console
from cli_tests.test_limbo_cli import TestTursoShell
from pydantic import BaseModel
sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ")
class CollateTest(BaseModel):
name: str
db_schema: str = """CREATE TABLE t1(
x INTEGER PRIMARY KEY,
a, /* collating sequence BINARY */
b COLLATE BINARY, /* collating sequence BINARY */
c COLLATE RTRIM, /* collating sequence RTRIM */
d COLLATE NOCASE /* collating sequence NOCASE */
);"""
db_path: str = "testing/collate.db"
def init_db(self):
with TestTursoShell(
init_commands="",
exec_name="sqlite3",
flags=f"{self.db_path}",
) as sqlite:
sqlite.execute_dot(f".open {self.db_path}")
stmt = [self.db_schema]
stmt = stmt + [
"INSERT INTO t1 VALUES(1,'abc','abc', 'abc ','abc');",
"INSERT INTO t1 VALUES(2,'abc','abc', 'abc', 'ABC');",
"INSERT INTO t1 VALUES(3,'abc','abc', 'abc ', 'Abc');",
"INSERT INTO t1 VALUES(4,'abc','abc ','ABC', 'abc');",
]
stmt.append("SELECT count(*) FROM t1;")
sqlite.run_test(
"Init Collate Db in Sqlite",
"".join(stmt),
f"{4}",
)
def run(self, limbo: TestTursoShell):
limbo.execute_dot(f".open {self.db_path}")
limbo.run_test(
"Text comparison a=b is performed using the BINARY collating sequence",
"SELECT x FROM t1 WHERE a = b ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 2, 3])),
)
limbo.run_test(
"Text comparison a=b is performed using the RTRIM collating sequence",
"SELECT x FROM t1 WHERE a = b COLLATE RTRIM ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 2, 3, 4])),
)
limbo.run_test(
"Text comparison d=a is performed using the NOCASE collating sequence",
"SELECT x FROM t1 WHERE d = a ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 2, 3, 4])),
)
limbo.run_test(
"Text comparison a=d is performed using the BINARY collating sequence.",
"SELECT x FROM t1 WHERE a = d ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 4])),
)
limbo.run_test(
"Text comparison 'abc'=c is performed using the RTRIM collating sequence.",
"SELECT x FROM t1 WHERE 'abc' = c ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 2, 3])),
)
limbo.run_test(
"Text comparison c='abc' is performed using the RTRIM collating sequence.",
"SELECT x FROM t1 WHERE c = 'abc' ORDER BY x;",
"\n".join(map(lambda x: str(x), [1, 2, 3])),
)
limbo.run_test(
"Grouping is performed using the NOCASE collating sequence (Values 'abc', 'ABC', and 'Abc' are placed in the same group).", # noqa: E501
"SELECT count(*) FROM t1 GROUP BY d ORDER BY 1;",
"\n".join(map(lambda x: str(x), [4])),
)
limbo.run_test(
"Grouping is performed using the BINARY collating sequence. 'abc' and 'ABC' and 'Abc' form different groups", # noqa: E501
"SELECT count(*) FROM t1 GROUP BY (d || '') ORDER BY 1;",
"\n".join(map(lambda x: str(x), [1, 1, 2])),
)
limbo.run_test(
"Sorting or column c is performed using the RTRIM collating sequence.",
"SELECT x FROM t1 ORDER BY c, x;",
"\n".join(map(lambda x: str(x), [4, 1, 2, 3])),
)
limbo.run_test(
"Sorting of (c||'') is performed using the BINARY collating sequence.",
"SELECT x FROM t1 ORDER BY (c||''), x;",
"\n".join(map(lambda x: str(x), [4, 2, 3, 1])),
)
limbo.run_test(
"Sorting of column c is performed using the NOCASE collating sequence.",
"SELECT x FROM t1 ORDER BY c COLLATE NOCASE, x;",
"\n".join(map(lambda x: str(x), [2, 4, 3, 1])),
)
def cleanup(db_fullpath: str):
wal_path = f"{db_fullpath}-wal"
shm_path = f"{db_fullpath}-shm"
paths = [db_fullpath, wal_path, shm_path]
for path in paths:
if os.path.exists(path):
os.remove(path)
def main():
# Test from using examples from Section 7.2
# https://sqlite.org/datatype3.html#collation
test = CollateTest(name="Smoke collate tests")
console.info(test)
db_path = test.db_path
try:
test.init_db()
# Use with syntax to automatically close shell on error
with TestTursoShell("") as limbo:
test.run(limbo)
# test.test_compat()
except Exception as e:
console.error(f"Test FAILED: {e}")
cleanup(db_path)
exit(1)
# delete db after every compat test so we we have fresh db for next test
cleanup(db_path)
console.info("All tests passed successfully.")
if __name__ == "__main__":
main()