chore: initial git load of code space
This commit is contained in:
@@ -0,0 +1,377 @@
|
||||
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.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.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.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.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.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.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
|
||||
Assert.That(success, Is.False);
|
||||
Assert.That(result, Is.Null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user