Files
sql-utilities/tests/Strata.SqlTools.Snowflake.Tests/Snowflake/StatementExpressionParserTests.cs
T
Thom LambandClaude Opus 4.7 67512d23e1 chore(sonar): wrap independent assertions in Assert.Multiple (NUnit2045)
Driven by `dotnet format analyzers --diagnostics NUnit2045`. The fixer
groups consecutive independent `Assert.That(...)` calls into
`Assert.Multiple(() => { ... })`, so a failing assertion no longer
short-circuits the block — every failure inside the group is reported,
which gives much better diagnostics on multi-property tests.

Audit confirmed no Assert.Throws / Assert.Fail / Assert.Catch / Assert.Pass
/ Assert.DoesNotThrow got pulled inside a Multiple block (those need to
short-circuit). All 1180 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 11:59:47 -05:00

399 lines
9.9 KiB
C#

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;
/// <summary>
/// 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.
/// </summary>
[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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<NumberLiteralExpression>());
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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<NumberLiteralExpression>());
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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<ColumnExpression>());
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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<ColumnExpression>());
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<AdditionExpression>());
}
[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<SubtractionExpression>());
}
[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<MultiplicationExpression>());
}
[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<DivisionExpression>());
}
[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<MultiplicationExpression>());
}
[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<MultiplicationExpression>());
}
#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<SumFunction>());
}
[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<AverageFunction>());
}
[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<SumFunction>());
}
#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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<ColumnExpression>());
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.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<ColumnExpression>());
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<SubtractionExpression>());
}
[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<AdditionExpression>());
}
#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<AdditionExpression>());
}
[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<MultiplicationExpression>());
}
[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<SubtractionExpression>());
}
#endregion
#region Error Handling Tests
[Test]
public void Parse_NullInput_ThrowsArgumentNullException()
{
// Arrange
string? sql = null;
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _parser.Parse(sql!));
}
[Test]
public void Parse_EmptyString_ThrowsArgumentNullException()
{
// Arrange
var sql = "";
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _parser.Parse(sql));
}
[Test]
public void Parse_Whitespace_ThrowsArgumentNullException()
{
// Arrange
var sql = " ";
// Act & Assert
Assert.Throws<ArgumentNullException>(() => _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.Multiple(() =>
{
// Assert
Assert.That(success, Is.False);
Assert.That(result, Is.Null);
});
}
#endregion
}