import subprocess
import json
import math
import pytest
from pathlib import Path
SQL_CLI = Path(__file__).parent.parent.parent / "target" / "release" / "sql-cli"
def run_query(query, output_format="json"):
cmd = [str(SQL_CLI), "-q", query, "-o", output_format]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"Command failed: {' '.join(cmd)}")
print(f"stderr: {result.stderr}")
raise Exception(f"Query failed: {result.stderr}")
if output_format == "json":
lines = result.stdout.strip().split('\n')
json_lines = [line for line in lines if not line.startswith('#') and line.strip()]
json_str = '\n'.join(json_lines)
if json_str:
return json.loads(json_str)
return result.stdout
class TestLengthConversions:
def test_kilometers_to_miles(self):
result = run_query("SELECT CONVERT(100, 'km', 'miles') as distance FROM DUAL")
assert abs(result[0]["distance"] - 62.137) < 0.01
def test_miles_to_kilometers(self):
result = run_query("SELECT CONVERT(100, 'miles', 'km') as distance FROM DUAL")
assert abs(result[0]["distance"] - 160.934) < 0.01
def test_feet_to_meters(self):
result = run_query("SELECT CONVERT(100, 'ft', 'm') as distance FROM DUAL")
assert abs(result[0]["distance"] - 30.48) < 0.01
def test_inches_to_centimeters(self):
result = run_query("SELECT CONVERT(12, 'in', 'cm') as distance FROM DUAL")
assert abs(result[0]["distance"] - 30.48) < 0.01
def test_nautical_miles_to_kilometers(self):
result = run_query("SELECT CONVERT(10, 'nmi', 'km') as distance FROM DUAL")
assert abs(result[0]["distance"] - 18.52) < 0.01
def test_micrometers_to_millimeters(self):
result = run_query("SELECT CONVERT(1000, 'um', 'mm') as distance FROM DUAL")
assert abs(result[0]["distance"] - 1.0) < 0.001
class TestMassConversions:
def test_pounds_to_kilograms(self):
result = run_query("SELECT CONVERT(100, 'lb', 'kg') as weight FROM DUAL")
assert abs(result[0]["weight"] - 45.359) < 0.01
def test_kilograms_to_pounds(self):
result = run_query("SELECT CONVERT(50, 'kg', 'lb') as weight FROM DUAL")
assert abs(result[0]["weight"] - 110.231) < 0.01
def test_ounces_to_grams(self):
result = run_query("SELECT CONVERT(16, 'oz', 'g') as weight FROM DUAL")
assert abs(result[0]["weight"] - 453.592) < 0.01
def test_metric_tons_to_pounds(self):
result = run_query("SELECT CONVERT(1, 'tonne', 'lb') as weight FROM DUAL")
assert abs(result[0]["weight"] - 2204.62) < 0.1
def test_milligrams_to_grams(self):
result = run_query("SELECT CONVERT(5000, 'mg', 'g') as weight FROM DUAL")
assert abs(result[0]["weight"] - 5.0) < 0.001
class TestTemperatureConversions:
def test_fahrenheit_to_celsius(self):
result = run_query("SELECT CONVERT(32, 'F', 'C') as temp FROM DUAL")
assert abs(result[0]["temp"] - 0.0) < 0.01
result = run_query("SELECT CONVERT(212, 'F', 'C') as temp FROM DUAL")
assert abs(result[0]["temp"] - 100.0) < 0.01
result = run_query("SELECT CONVERT(72, 'F', 'C') as temp FROM DUAL")
assert abs(result[0]["temp"] - 22.22) < 0.1
def test_celsius_to_fahrenheit(self):
result = run_query("SELECT CONVERT(0, 'C', 'F') as temp FROM DUAL")
assert abs(result[0]["temp"] - 32.0) < 0.01
result = run_query("SELECT CONVERT(100, 'C', 'F') as temp FROM DUAL")
assert abs(result[0]["temp"] - 212.0) < 0.01
def test_celsius_to_kelvin(self):
result = run_query("SELECT CONVERT(0, 'C', 'K') as temp FROM DUAL")
assert abs(result[0]["temp"] - 273.15) < 0.01
result = run_query("SELECT CONVERT(100, 'C', 'K') as temp FROM DUAL")
assert abs(result[0]["temp"] - 373.15) < 0.01
def test_kelvin_to_celsius(self):
result = run_query("SELECT CONVERT(273.15, 'K', 'C') as temp FROM DUAL")
assert abs(result[0]["temp"] - 0.0) < 0.01
result = run_query("SELECT CONVERT(373.15, 'K', 'C') as temp FROM DUAL")
assert abs(result[0]["temp"] - 100.0) < 0.01
class TestVolumeConversions:
def test_gallons_to_liters(self):
result = run_query("SELECT CONVERT(1, 'gal', 'L') as volume FROM DUAL")
assert abs(result[0]["volume"] - 3.785) < 0.01
def test_liters_to_gallons(self):
result = run_query("SELECT CONVERT(10, 'L', 'gal') as volume FROM DUAL")
assert abs(result[0]["volume"] - 2.642) < 0.01
def test_cups_to_milliliters(self):
result = run_query("SELECT CONVERT(1, 'cup', 'ml') as volume FROM DUAL")
assert abs(result[0]["volume"] - 236.588) < 0.1
def test_tablespoons_to_milliliters(self):
result = run_query("SELECT CONVERT(1, 'tbsp', 'ml') as volume FROM DUAL")
assert abs(result[0]["volume"] - 14.787) < 0.1
def test_cubic_meters_to_liters(self):
result = run_query("SELECT CONVERT(1, 'm3', 'L') as volume FROM DUAL")
assert abs(result[0]["volume"] - 1000.0) < 0.01
class TestTimeConversions:
def test_hours_to_minutes(self):
result = run_query("SELECT CONVERT(2.5, 'hour', 'min') as time FROM DUAL")
assert abs(result[0]["time"] - 150.0) < 0.01
def test_days_to_hours(self):
result = run_query("SELECT CONVERT(3, 'days', 'hours') as time FROM DUAL")
assert abs(result[0]["time"] - 72.0) < 0.01
def test_milliseconds_to_seconds(self):
result = run_query("SELECT CONVERT(5000, 'ms', 's') as time FROM DUAL")
assert abs(result[0]["time"] - 5.0) < 0.01
def test_weeks_to_days(self):
result = run_query("SELECT CONVERT(2, 'weeks', 'days') as time FROM DUAL")
assert abs(result[0]["time"] - 14.0) < 0.01
def test_years_to_days(self):
result = run_query("SELECT CONVERT(1, 'year', 'days') as time FROM DUAL")
assert abs(result[0]["time"] - 365.25) < 0.01
class TestAreaConversions:
def test_square_feet_to_square_meters(self):
result = run_query("SELECT CONVERT(100, 'sq_ft', 'm2') as area FROM DUAL")
assert abs(result[0]["area"] - 9.290) < 0.01
def test_acres_to_hectares(self):
result = run_query("SELECT CONVERT(10, 'acres', 'hectares') as area FROM DUAL")
assert abs(result[0]["area"] - 4.047) < 0.01
def test_square_miles_to_square_kilometers(self):
result = run_query("SELECT CONVERT(1, 'sq_mi', 'km2') as area FROM DUAL")
assert abs(result[0]["area"] - 2.590) < 0.01
class TestSpeedConversions:
def test_mph_to_kph(self):
result = run_query("SELECT CONVERT(60, 'mph', 'kph') as speed FROM DUAL")
assert abs(result[0]["speed"] - 96.561) < 0.1
def test_knots_to_mph(self):
result = run_query("SELECT CONVERT(100, 'knots', 'mph') as speed FROM DUAL")
assert abs(result[0]["speed"] - 115.078) < 0.1
def test_meters_per_second_to_kph(self):
result = run_query("SELECT CONVERT(10, 'm/s', 'kph') as speed FROM DUAL")
assert abs(result[0]["speed"] - 36.0) < 0.01
class TestPressureConversions:
def test_psi_to_bar(self):
result = run_query("SELECT CONVERT(30, 'psi', 'bar') as pressure FROM DUAL")
assert abs(result[0]["pressure"] - 2.068) < 0.01
def test_atmospheres_to_pascal(self):
result = run_query("SELECT CONVERT(1, 'atm', 'Pa') as pressure FROM DUAL")
assert abs(result[0]["pressure"] - 101325.0) < 1.0
def test_torr_to_millibar(self):
result = run_query("SELECT CONVERT(760, 'torr', 'mbar') as pressure FROM DUAL")
assert abs(result[0]["pressure"] - 1013.25) < 0.1
class TestMixedCalculations:
def test_fuel_efficiency_conversion(self):
result = run_query("""
SELECT
CONVERT(100, 'km', 'miles') as km_to_miles,
CONVERT(1, 'gal', 'L') as gal_to_L,
(CONVERT(100, 'km', 'miles') / 30.0) * CONVERT(1, 'gal', 'L') as L_per_100km
FROM DUAL
""")
assert abs(result[0]["L_per_100km"] - 7.84) < 0.1
def test_bmi_calculation_imperial_to_metric(self):
result = run_query("""
SELECT
CONVERT(180, 'lb', 'kg') as weight_kg,
CONVERT(72, 'in', 'm') as height_m,
CONVERT(180, 'lb', 'kg') / (CONVERT(72, 'in', 'm') * CONVERT(72, 'in', 'm')) as bmi
FROM DUAL
""")
assert abs(result[0]["bmi"] - 24.4) < 0.2
def test_physics_calculation_with_units(self):
result = run_query("""
SELECT
CONVERT(2000, 'lb', 'kg') as mass_kg,
CONVERT(60, 'mph', 'm/s') as speed_ms,
0.5 * CONVERT(2000, 'lb', 'kg') * CONVERT(60, 'mph', 'm/s') * CONVERT(60, 'mph', 'm/s') as KE_joules
FROM DUAL
""")
assert abs(result[0]["KE_joules"] - 326000) < 5000
class TestEdgeCases:
def test_case_insensitive_units(self):
result1 = run_query("SELECT CONVERT(100, 'KM', 'MILES') as d1 FROM DUAL")
result2 = run_query("SELECT CONVERT(100, 'km', 'miles') as d2 FROM DUAL")
result3 = run_query("SELECT CONVERT(100, 'Km', 'Miles') as d3 FROM DUAL")
assert abs(result1[0]["d1"] - result2[0]["d2"]) < 0.001
assert abs(result2[0]["d2"] - result3[0]["d3"]) < 0.001
def test_unit_aliases(self):
result1 = run_query("SELECT CONVERT(10, 'kilometer', 'mi') as d FROM DUAL")
result2 = run_query("SELECT CONVERT(10, 'kilometers', 'mile') as d FROM DUAL")
result3 = run_query("SELECT CONVERT(10, 'km', 'miles') as d FROM DUAL")
assert abs(result1[0]["d"] - result2[0]["d"]) < 0.001
assert abs(result2[0]["d"] - result3[0]["d"]) < 0.001
def test_precision_preservation(self):
result = run_query("""
SELECT
CONVERT(1, 'm', 'mm') as to_mm,
CONVERT(CONVERT(1, 'm', 'mm'), 'mm', 'm') as back_to_m
FROM DUAL
""")
assert result[0]["to_mm"] == 1000.0
assert abs(result[0]["back_to_m"] - 1.0) < 1e-10
if __name__ == "__main__":
pytest.main([__file__, "-v"])