"""Unit tests for the Alteryx → DuckDB expression transpiler.""" from __future__ import annotations import sys from pathlib import Path import pytest PKG = Path(__file__).parent.parent # alteryx_runner/ if str(PKG) not in sys.path: sys.path.insert(0, str(PKG)) from expression.transpiler import transpile, UnsupportedExpressionError def t(expr: str) -> str: return transpile(expr) class TestLiterals: def test_number(self): assert t("42") == "42" def test_float(self): assert t("3.14") == "3.14" def test_string(self): assert t('"hello"') == "'hello'" def test_null(self): assert t("NULL()") == "NULL" def test_true(self): assert t("True") == "TRUE" def test_false(self): assert t("False") == "FALSE" class TestColumnRef: def test_simple(self): assert t("[CustomerID]") == '"CustomerID"' def test_spaces(self): assert t("[First Name]") == '"First Name"' class TestOperators: def test_eq(self): assert t("[A] == [B]") == '("A" = "B")' def test_neq(self): assert t("[A] != [B]") == '("A" <> "B")' def test_gt(self): assert t("[Score] > 50") == '("Score" > 50)' def test_and(self): sql = t('[A] > 0 AND [B] < 10') assert "AND" in sql def test_or(self): sql = t('[A] > 0 OR [B] < 0') assert "OR" in sql def test_not(self): sql = t('NOT [IsActive]') assert "NOT" in sql def test_bang(self): sql = t('![IsActive]') assert "NOT" in sql class TestIfThenEndif: def test_simple(self): sql = t('IF [Score] > 50 THEN "Pass" ELSE "Fail" ENDIF') assert "CASE WHEN" in sql assert "'Pass'" in sql assert "'Fail'" in sql def test_elseif(self): sql = t('IF [Score] > 90 THEN "A" ELSEIF [Score] > 70 THEN "B" ELSE "C" ENDIF') assert sql.count("WHEN") == 2 def test_no_else(self): sql = t('IF [Active] == "Y" THEN "Yes" ENDIF') assert "CASE WHEN" in sql class TestIIF: def test_iif(self): sql = t('IIF([Score] > 50, "Pass", "Fail")') assert "CASE WHEN" in sql class TestIsNull: def test_isnull_keyword(self): sql = t('IsNull([Field])') assert "IS NULL" in sql def test_not_isnull(self): sql = t('!IsNull([Field])') assert "NOT" in sql and "IS NULL" in sql class TestFunctions: def test_uppercase(self): assert t('Uppercase([Name])') == "UPPER(\"Name\")" def test_length(self): assert "LENGTH" in t('Length([Name])') def test_left(self): assert "LEFT" in t('Left([Name], 3)') def test_round(self): assert "ROUND" in t('Round([Score], 2)') def test_abs(self): assert "ABS" in t('ABS([Val])') def test_trim(self): assert "TRIM" in t('Trim([Name])') def test_nested(self): sql = t('Uppercase(Trim([Name]))') assert "UPPER" in sql assert "TRIM" in sql class TestArithmetic: def test_add(self): sql = t('[A] + [B]') assert "+" in sql def test_multiply(self): sql = t('[A] * [B]') assert "*" in sql def test_divide(self): sql = t('[A] / [B]') assert "/" in sql def test_complex(self): sql = t('ROUND([Spend] / [Visits], 1)') assert "ROUND" in sql class TestDateFunctions: def test_datetimenow(self): sql = t('DateTimeNow()') assert "NOW()" in sql def test_datetimetoday(self): sql = t('DateTimeToday()') assert "CURRENT_DATE" in sql