import subprocess
import csv
import io
import hashlib
from pathlib import Path
import tempfile
SQL_CLI = Path(__file__).parent.parent.parent / "target" / "release" / "sql-cli"
def run_query(csv_file, query):
result = subprocess.run(
[str(SQL_CLI), str(csv_file), "-q", query, "-o", "csv"],
capture_output=True,
text=True
)
if result.returncode != 0:
raise Exception(f"Query failed: {result.stderr}")
output_lines = result.stdout.strip().split('\n')
csv_lines = [line for line in output_lines if not line.startswith('#')]
if not csv_lines:
return []
reader = csv.DictReader(io.StringIO('\n'.join(csv_lines)))
return list(reader)
def test_md5():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("text\n")
f.write("hello\n")
f.write("world\n")
f.write("test123\n")
f.write("\n") temp_file = f.name
try:
query = "SELECT text, MD5(text) as hash FROM test"
results = run_query(temp_file, query)
for row in results:
text = row['text']
expected = hashlib.md5(text.encode()).hexdigest()
assert row['hash'] == expected, f"MD5 mismatch for '{text}': {row['hash']} != {expected}"
print("✓ test_md5 passed")
finally:
Path(temp_file).unlink()
def test_sha1():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("text\n")
f.write("hello\n")
f.write("test\n")
f.write("sql-cli\n")
temp_file = f.name
try:
query = "SELECT text, SHA1(text) as hash FROM test"
results = run_query(temp_file, query)
for row in results:
text = row['text']
expected = hashlib.sha1(text.encode()).hexdigest()
assert row['hash'] == expected, f"SHA1 mismatch for '{text}': {row['hash']} != {expected}"
print("✓ test_sha1 passed")
finally:
Path(temp_file).unlink()
def test_sha256():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("text\n")
f.write("hello\n")
f.write("SHA256 test\n")
f.write("1234567890\n")
temp_file = f.name
try:
query = "SELECT text, SHA256(text) as hash FROM test"
results = run_query(temp_file, query)
for row in results:
text = row['text']
expected = hashlib.sha256(text.encode()).hexdigest()
assert row['hash'] == expected, f"SHA256 mismatch for '{text}': {row['hash']} != {expected}"
print("✓ test_sha256 passed")
finally:
Path(temp_file).unlink()
def test_sha512():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("text\n")
f.write("hello\n")
f.write("SHA512 test\n")
f.write("\n") temp_file = f.name
try:
query = "SELECT text, SHA512(text) as hash FROM test"
results = run_query(temp_file, query)
for row in results:
text = row['text']
expected = hashlib.sha512(text.encode()).hexdigest()
assert row['hash'] == expected, f"SHA512 mismatch for '{text}': {row['hash']} != {expected}"
print("✓ test_sha512 passed")
finally:
Path(temp_file).unlink()
def test_null_handling():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("id,text\n")
f.write("1,hello\n")
f.write("2,\n") temp_file = f.name
try:
for func in ['MD5', 'SHA1', 'SHA256', 'SHA512']:
query = f"SELECT id, {func}(text) as hash FROM test WHERE id = 2"
results = run_query(temp_file, query)
assert results[0]['hash'] == '', f"{func} should return NULL for NULL input"
query = "SELECT MD5(123) as hash"
results = run_query(temp_file, query)
expected = hashlib.md5('123'.encode()).hexdigest()
assert results[0]['hash'] == expected, f"MD5 of number should work"
print("✓ test_null_handling passed")
finally:
Path(temp_file).unlink()
def test_case_sensitivity():
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
f.write("text\n")
f.write("Hello\n")
f.write("hello\n")
f.write("HELLO\n")
temp_file = f.name
try:
query = "SELECT text, MD5(text) as hash FROM test"
results = run_query(temp_file, query)
hashes = [r['hash'] for r in results]
assert len(hashes) == len(set(hashes)), "Different cases should produce different hashes"
print("✓ test_case_sensitivity passed")
finally:
Path(temp_file).unlink()
def main():
print("Running hash function tests...")
if not SQL_CLI.exists():
print(f"Error: sql-cli not found at {SQL_CLI}")
print("Please run: cargo build --release")
return 1
tests = [
test_md5,
test_sha1,
test_sha256,
test_sha512,
test_null_handling,
test_case_sensitivity,
]
failed = 0
for test in tests:
try:
test()
except Exception as e:
print(f"✗ {test.__name__} failed: {e}")
failed += 1
if failed == 0:
print(f"\n✅ All {len(tests)} hash function tests passed!")
else:
print(f"\n❌ {failed}/{len(tests)} tests failed")
return 1
return 0
if __name__ == "__main__":
exit(main())