using Strata.SqlTools.SqlBreakdown.Expressions; using Strata.SqlTools.SqlBreakdown.Expressions.Arithmetic; using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate; using Strata.SqlTools.SqlBreakdown.Expressions.Literals; namespace Strata.SqlTools.SqlBreakdown.Tests.Snowflake; /// /// Tests for Snowflake SQL statement expression parser. /// Note: The parser currently only supports identifiers enclosed in double quotes ("ID") /// or brackets ([ID]). Unquoted identifiers and spaces in identifiers are not supported yet. /// [TestFixture] public class StatementExpressionParserTests { private Strata.SqlTools.Statements.Snowflake.StatementExpressionParser _parser = null!; [SetUp] public void SetUp() { _parser = new Strata.SqlTools.Statements.Snowflake.StatementExpressionParser(); } #region Basic Tests [Test] public void Parse_Number_ReturnsNumberExpression() { // Arrange var sql = "42"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((NumberLiteralExpression)result).Value, Is.EqualTo(42)); } [Test] public void Parse_DecimalNumber_ReturnsNumberExpression() { // Arrange var sql = "3.14"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((NumberLiteralExpression)result).Value, Is.EqualTo(3.14m)); } [Test] public void Parse_DoubleQuotedIdentifier_ReturnsColumnExpression() { // Arrange - Snowflake convention: double-quoted identifiers var sql = "\"CUSTOMER_ID\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((ColumnExpression)result).ColumnName, Is.EqualTo("CUSTOMER_ID")); } [Test] public void Parse_BracketedIdentifier_ReturnsColumnExpression() { // Arrange - Also supports SQL Server bracket style var sql = "[CUSTOMER_ID]"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((ColumnExpression)result).ColumnName, Is.EqualTo("CUSTOMER_ID")); } #endregion #region Arithmetic Tests [Test] public void Parse_Addition_ReturnsAdditionExpression() { // Arrange var sql = "\"REVENUE\" + \"COST\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_Subtraction_ReturnsSubtractionExpression() { // Arrange var sql = "\"REVENUE\" - \"COST\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_Multiplication_ReturnsMultiplicationExpression() { // Arrange var sql = "\"PRICE\" * \"QUANTITY\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_Division_ReturnsDivisionExpression() { // Arrange var sql = "\"TOTAL\" / \"COUNT\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_ColumnWithNumber_ReturnsCorrectExpression() { // Arrange var sql = "\"NET_REVENUE\" * 1.15"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_ComplexArithmetic_ReturnsCorrectExpression() { // Arrange var sql = "(\"BASE_PRICE\" + \"TAX_AMOUNT\") * \"QUANTITY\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } #endregion #region Function Tests [Test] public void Parse_SumFunction_ReturnsSumFunctionExpression() { // Arrange var sql = "SUM(\"REVENUE\")"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_AvgFunction_ReturnsAverageFunctionExpression() { // Arrange var sql = "AVG(\"REVENUE\")"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_FunctionWithExpression_ReturnsCorrectExpression() { // Arrange var sql = "SUM(\"NET_REVENUE\" * 1.1)"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } #endregion #region Snowflake-Specific Syntax Tests [Test] public void Parse_UppercaseIdentifier_ReturnsColumnExpression() { // Arrange - Snowflake convention: identifiers typically uppercase var sql = "\"ORDER_TOTAL\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((ColumnExpression)result).ColumnName, Is.EqualTo("ORDER_TOTAL")); } [Test] public void Parse_IdentifierWithUnderscores_ReturnsColumnExpression() { // Arrange - Snowflake naming: underscores common var sql = "\"NET_REVENUE_USD_2024\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); Assert.That(((ColumnExpression)result).ColumnName, Is.EqualTo("NET_REVENUE_USD_2024")); } [Test] public void Parse_MixedQuotingStyles_ReturnsCorrectExpression() { // Arrange - Mix of double-quoted and bracketed identifiers var sql = "SUM(\"GROSS_REVENUE\") - [COST]"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_MultipleDoubleQuotedIdentifiers_ReturnsCorrectExpression() { // Arrange var sql = "\"A\" + \"B\" * \"C\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } #endregion #region Parentheses and Precedence Tests [Test] public void Parse_SimpleParentheses_ReturnsCorrectExpression() { // Arrange var sql = "(\"A\" + \"B\")"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_ParenthesesWithMultiplication_ReturnsCorrectPrecedence() { // Arrange var sql = "(1 + 2) * 3"; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_NestedParentheses_ReturnsCorrectExpression() { // Arrange var sql = "((\"A\" + \"B\") * \"C\") - \"D\""; // Act var result = _parser.Parse(sql); // Assert Assert.That(result, Is.Not.Null); Assert.That(result, Is.InstanceOf()); } #endregion #region Error Handling Tests [Test] public void Parse_NullInput_ThrowsArgumentNullException() { // Arrange string? sql = null; // Act & Assert Assert.Throws(() => _parser.Parse(sql!)); } [Test] public void Parse_EmptyString_ThrowsArgumentNullException() { // Arrange var sql = ""; // Act & Assert Assert.Throws(() => _parser.Parse(sql)); } [Test] public void Parse_Whitespace_ThrowsArgumentNullException() { // Arrange var sql = " "; // Act & Assert Assert.Throws(() => _parser.Parse(sql)); } [Test] public void TryParse_InvalidSyntax_ReturnsFalse() { // Arrange var sql = "\"A\" +"; // Incomplete expression // Act var success = _parser.TryParse(sql, out var result); // Assert Assert.That(success, Is.False); Assert.That(result, Is.Null); } #endregion }