test(sql): Add comprehensive unit tests for breakdown classes and utilities

Introduces new unit tests for Snowflake and SQL Server-specific SQL breakdown
classes (DELETE, INSERT, UPDATE, PROCEDURE) and various general SQL utility
functions. This significantly increases test coverage, ensuring robustness
and correctness across different SQL dialects and helper logic.
This commit is contained in:
Thom Lamb
2026-06-15 08:16:22 -05:00
parent 9f9450dc6d
commit fbedea3941
13 changed files with 2575 additions and 0 deletions
@@ -0,0 +1,172 @@
using Strata.SqlTools.Breakdowns.Snowflake;
namespace Strata.SqlTools.SqlBreakdown.Tests.Snowflake;
[TestFixture]
public class DeleteBreakdownTests
{
#region Constructor Tests
[Test]
public void Constructor_Default_InitializesEmptyClauses()
{
// Arrange & Act
var breakdown = new DeleteBreakdown();
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.FromClause.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.IsUsingWhereClause, Is.False);
});
}
[Test]
public void Constructor_WithClauses_SetsProperties()
{
// Arrange & Act
var breakdown = new DeleteBreakdown("USERS", "ID = :ID");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("ID = :ID"));
Assert.That(breakdown.IsUsingWhereClause, Is.True);
});
}
#endregion
#region GetSql Tests
[Test]
public void GetSql_WithWhere_RendersDeleteFromWhere()
{
// Arrange - Snowflake overrides the formatter with simplified DELETE FROM syntax
var breakdown = new DeleteBreakdown("USERS", "ID = :ID");
// Act
var sql = breakdown.GetSql();
Assert.Multiple(() =>
{
// Assert
Assert.That(sql, Does.Contain("DELETE FROM"));
Assert.That(sql, Does.Contain("USERS"));
Assert.That(sql, Does.Contain("WHERE"));
Assert.That(sql, Does.Contain("ID = :ID"));
});
}
[Test]
public void GetSql_WithoutWhere_OmitsWhereKeyword()
{
// Arrange
var breakdown = new DeleteBreakdown("USERS", string.Empty);
// Act
var sql = breakdown.GetSql();
Assert.Multiple(() =>
{
// Assert
Assert.That(sql, Does.Contain("DELETE FROM"));
Assert.That(sql, Does.Not.Contain("WHERE"));
});
}
#endregion
#region Parse Tests
[Test]
public void Parse_SnowflakeDelete_PopulatesClauses()
{
// Arrange
var input = "DELETE FROM USERS WHERE ID = 1";
// Act
var breakdown = DeleteBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("ID = 1"));
});
}
[Test]
public void Parse_DeleteWithoutWhere_LeavesWhereEmpty()
{
// Act
var breakdown = DeleteBreakdown.Parse("DELETE FROM USERS");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.IsUsingWhereClause, Is.False);
});
}
[Test]
public void Parse_MicrosoftSqlMode_DelegatesToBase()
{
// Act - T-SQL DELETE with alias is supported through the base breakdown
var breakdown = DeleteBreakdown.Parse("DELETE FROM Users WHERE Id = 1", isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown, Is.InstanceOf<DeleteBreakdown>());
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("Users"));
});
}
[Test]
public void Parse_NullOrWhitespace_ThrowsArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => DeleteBreakdown.Parse(null!));
}
[Test]
public void Parse_NotADeleteStatement_ThrowsFormatException()
{
// Act & Assert
Assert.Throws<FormatException>(() => DeleteBreakdown.Parse("SELECT * FROM USERS"));
}
[Test]
public void TryParse_MicrosoftSqlMode_ReturnsSnowflakeInstance()
{
// Act
var success = DeleteBreakdown.TryParse("DELETE FROM Users WHERE Id = 1", out var breakdown, isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.True);
Assert.That(breakdown, Is.InstanceOf<DeleteBreakdown>());
});
}
[Test]
public void TryParse_WrongPrefix_ReturnsFalse()
{
// Act
var success = DeleteBreakdown.TryParse("UPDATE USERS SET ID = 1", out _, out var error);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.False);
Assert.That(error, Does.Contain("DELETE"));
});
}
#endregion
}
@@ -0,0 +1,151 @@
using Strata.SqlTools.Breakdowns.Snowflake;
namespace Strata.SqlTools.SqlBreakdown.Tests.Snowflake;
[TestFixture]
public class InsertBreakdownTests
{
#region Constructor Tests
[Test]
public void Constructor_Default_InitializesEmptyClauses()
{
// Arrange & Act
var breakdown = new InsertBreakdown();
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.InsertIntoClause.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.ValuesClause.Clause, Is.EqualTo(string.Empty));
});
}
[Test]
public void Constructor_WithClauses_SetsProperties()
{
// Arrange & Act
var breakdown = new InsertBreakdown("USERS", "ID, NAME", ":ID, :NAME");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.InsertIntoClause.Clause, Is.EqualTo("ID, NAME"));
Assert.That(breakdown.ValuesClause.Clause, Is.EqualTo(":ID, :NAME"));
});
}
[Test]
public void Constructor_WithColumnNames_GeneratesColonPrefixedParameters()
{
// Arrange & Act - Snowflake uses :parameter syntax (vs SQL Server's @parameter)
var breakdown = new InsertBreakdown("USERS", new List<string> { "ID", "NAME" });
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.InsertIntoClause.Clause, Is.EqualTo("[ID],[NAME]"));
Assert.That(breakdown.ValuesClause.Clause, Is.EqualTo(":ID,:NAME"));
});
}
#endregion
#region Parse Tests
[Test]
public void Parse_SnowflakeInsert_PopulatesClauses()
{
// Arrange
var input = "INSERT INTO USERS (ID, NAME) VALUES (1, 'BOB')";
// Act
var breakdown = InsertBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.InsertIntoClause.Clause, Is.EqualTo("ID, NAME"));
Assert.That(breakdown.ValuesClause.Clause, Is.EqualTo("1, 'BOB'"));
});
}
[Test]
public void Parse_MicrosoftSqlMode_DelegatesToBaseAndSucceeds()
{
// Arrange
var input = "INSERT INTO Users (Id) VALUES (1)";
// Act
var breakdown = InsertBreakdown.Parse(input, isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown, Is.InstanceOf<InsertBreakdown>());
Assert.That(breakdown.TableName.Clause, Is.EqualTo("Users"));
Assert.That(breakdown.InsertIntoClause.Clause, Is.EqualTo("Id"));
});
}
[Test]
public void Parse_NullOrWhitespace_ThrowsArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => InsertBreakdown.Parse(" "));
}
[Test]
public void Parse_NotAnInsertStatement_ThrowsFormatException()
{
// Act & Assert
Assert.Throws<FormatException>(() => InsertBreakdown.Parse("SELECT * FROM USERS"));
}
[Test]
public void TryParse_ValidInsert_ReturnsTrue()
{
// Act
var success = InsertBreakdown.TryParse("INSERT INTO USERS (ID) VALUES (1)", out var breakdown);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.True);
Assert.That(breakdown.TableName.Clause, Is.EqualTo("USERS"));
});
}
[Test]
public void TryParse_MicrosoftSqlMode_ReturnsSnowflakeInstance()
{
// Act
var success = InsertBreakdown.TryParse("INSERT INTO Users (Id) VALUES (1)", out var breakdown, isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.True);
Assert.That(breakdown, Is.InstanceOf<InsertBreakdown>());
});
}
[Test]
public void TryParse_WrongPrefix_ReturnsFalse()
{
// Act
var success = InsertBreakdown.TryParse("DELETE FROM USERS", out _, out var error);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.False);
Assert.That(error, Does.Contain("INSERT INTO"));
});
}
#endregion
}
@@ -0,0 +1,193 @@
using Strata.SqlTools.Breakdowns.Snowflake;
namespace Strata.SqlTools.SqlBreakdown.Tests.Snowflake;
[TestFixture]
public class ProcedureBreakdownTests
{
#region Constructor Tests
[Test]
public void Constructor_WithName_SetsProcedureName()
{
// Arrange & Act
var breakdown = new ProcedureBreakdown("MY_PROC");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("MY_PROC"));
Assert.That(breakdown.IsUsingParameters, Is.False);
});
}
[Test]
public void Constructor_WithParameters_SetsParameters()
{
// Arrange
var parameters = new Dictionary<string, string> { ["@ID"] = "1" };
// Act
var breakdown = new ProcedureBreakdown("MY_PROC", parameters);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.IsUsingParameters, Is.True);
Assert.That(breakdown.Parameters["@ID"], Is.EqualTo("1"));
});
}
#endregion
#region GetSql Tests - Snowflake CALL Syntax
[Test]
public void GetSql_WithoutParameters_RendersCallWithEmptyParens()
{
// Arrange - Snowflake uses CALL proc() rather than EXEC proc
var breakdown = new ProcedureBreakdown("MY_PROC");
// Act
var sql = breakdown.GetSql();
Assert.Multiple(() =>
{
// Assert
Assert.That(sql, Does.Contain("CALL"));
Assert.That(sql, Does.Contain("MY_PROC"));
Assert.That(sql, Does.Contain("()"));
Assert.That(sql, Does.Not.Contain("EXEC"));
});
}
[Test]
public void GetSql_WithParameters_RendersNamedArrowSyntax()
{
// Arrange
var breakdown = new ProcedureBreakdown("MY_PROC");
breakdown.AddParameter("@ID", "1");
// Act - Snowflake named-parameter syntax strips @ and uses =>
var sql = breakdown.GetSql();
Assert.Multiple(() =>
{
// Assert
Assert.That(sql, Does.Contain("CALL"));
Assert.That(sql, Does.Contain("ID => 1"));
});
}
#endregion
#region Parse Tests - Snowflake CALL
[Test]
public void Parse_CallWithoutParameters_PopulatesName()
{
// Act
var breakdown = ProcedureBreakdown.Parse("CALL MY_PROC()");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("MY_PROC"));
Assert.That(breakdown.IsUsingParameters, Is.False);
});
}
[Test]
public void Parse_CallWithNamedParameters_PopulatesParametersWithAtPrefix()
{
// Arrange
var input = "CALL MY_PROC(ID => 1, NAME => 'BOB')";
// Act
var breakdown = ProcedureBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert - parsed named params are stored with @ prefix for consistency
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("MY_PROC"));
Assert.That(breakdown.Parameters["@ID"], Is.EqualTo("1"));
Assert.That(breakdown.Parameters["@NAME"], Is.EqualTo("'BOB'"));
});
}
[Test]
public void Parse_CallWithPositionalParameters_GeneratesParamNames()
{
// Arrange - no => present, so values are treated positionally
var input = "CALL MY_PROC(1, 'BOB')";
// Act
var breakdown = ProcedureBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.Parameters["@param1"], Is.EqualTo("1"));
Assert.That(breakdown.Parameters["@param2"], Is.EqualTo("'BOB'"));
});
}
[Test]
public void Parse_MicrosoftSqlMode_AcceptsExecSyntax()
{
// Act - T-SQL EXEC is parsed via base-class delegation
var breakdown = ProcedureBreakdown.Parse("EXEC dbo.GetUser @Id = 1", isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown, Is.InstanceOf<ProcedureBreakdown>());
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUser"));
Assert.That(breakdown.Parameters["@Id"], Is.EqualTo("1"));
});
}
[Test]
public void Parse_NullOrWhitespace_ThrowsArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => ProcedureBreakdown.Parse(" "));
}
[Test]
public void Parse_NotACallStatement_ThrowsFormatException()
{
// Act & Assert
Assert.Throws<FormatException>(() => ProcedureBreakdown.Parse("SELECT * FROM USERS"));
}
[Test]
public void TryParse_ValidCall_ReturnsTrue()
{
// Act
var success = ProcedureBreakdown.TryParse("CALL MY_PROC()", out var breakdown);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.True);
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("MY_PROC"));
});
}
[Test]
public void TryParse_WrongPrefix_ReturnsFalseWithMessage()
{
// Act
var success = ProcedureBreakdown.TryParse("SELECT 1", out _, out var error);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.False);
Assert.That(error, Does.Contain("CALL"));
});
}
#endregion
}
@@ -0,0 +1,161 @@
using Strata.SqlTools.Breakdowns.Snowflake;
namespace Strata.SqlTools.SqlBreakdown.Tests.Snowflake;
[TestFixture]
public class UpdateBreakdownTests
{
#region Constructor Tests
[Test]
public void Constructor_Default_InitializesEmptyClauses()
{
// Arrange & Act
var breakdown = new UpdateBreakdown();
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.SetClause.Clause, Is.EqualTo(string.Empty));
Assert.That(breakdown.IsUsingWhereClause, Is.False);
});
}
[Test]
public void Constructor_WithClauses_SetsProperties()
{
// Arrange & Act
var breakdown = new UpdateBreakdown("USERS", "NAME = :NAME", "ID = :ID");
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.SetClause.Clause, Is.EqualTo("NAME = :NAME"));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("ID = :ID"));
});
}
#endregion
#region GetSql Tests
[Test]
public void GetSql_RendersUpdateSetWhere()
{
// Arrange - Snowflake inherits the SQL Server UPDATE formatter
var breakdown = new UpdateBreakdown("USERS", "NAME = :NAME", "ID = :ID");
// Act
var sql = breakdown.GetSql();
Assert.Multiple(() =>
{
// Assert
Assert.That(sql, Does.Contain("UPDATE"));
Assert.That(sql, Does.Contain("USERS"));
Assert.That(sql, Does.Contain("SET"));
Assert.That(sql, Does.Contain("NAME = :NAME"));
Assert.That(sql, Does.Contain("WHERE"));
});
}
#endregion
#region Parse Tests
[Test]
public void Parse_SnowflakeUpdate_PopulatesClauses()
{
// Arrange
var input = "UPDATE USERS SET NAME = 'BOB' WHERE ID = 1";
// Act
var breakdown = UpdateBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.TableName.Clause, Is.EqualTo("USERS"));
Assert.That(breakdown.SetClause.Clause, Is.EqualTo("NAME = 'BOB'"));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("ID = 1"));
});
}
[Test]
public void Parse_UpdateWithFrom_PopulatesFromClause()
{
// Arrange
var input = "UPDATE T SET T.NAME = S.NAME FROM TARGET T INNER JOIN SOURCE S ON T.ID = S.ID WHERE S.ACTIVE = 1";
// Act
var breakdown = UpdateBreakdown.Parse(input);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown.IsUsingFromClause, Is.True);
Assert.That(breakdown.FromClause.Clause, Does.Contain("INNER JOIN SOURCE"));
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("S.ACTIVE = 1"));
});
}
[Test]
public void Parse_MicrosoftSqlMode_DelegatesToBase()
{
// Act
var breakdown = UpdateBreakdown.Parse("UPDATE Users SET Name = 'Bob' WHERE Id = 1", isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(breakdown, Is.InstanceOf<UpdateBreakdown>());
Assert.That(breakdown.TableName.Clause, Is.EqualTo("Users"));
});
}
[Test]
public void Parse_NullOrWhitespace_ThrowsArgumentNullException()
{
// Act & Assert
Assert.Throws<ArgumentNullException>(() => UpdateBreakdown.Parse(string.Empty));
}
[Test]
public void Parse_NotAnUpdateStatement_ThrowsFormatException()
{
// Act & Assert
Assert.Throws<FormatException>(() => UpdateBreakdown.Parse("SELECT * FROM USERS"));
}
[Test]
public void TryParse_MicrosoftSqlMode_ReturnsSnowflakeInstance()
{
// Act
var success = UpdateBreakdown.TryParse("UPDATE Users SET Name = 'Bob'", out var breakdown, isMicrosoftSql: true);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.True);
Assert.That(breakdown, Is.InstanceOf<UpdateBreakdown>());
});
}
[Test]
public void TryParse_WrongPrefix_ReturnsFalse()
{
// Act
var success = UpdateBreakdown.TryParse("DELETE FROM USERS", out _, out var error);
Assert.Multiple(() =>
{
// Assert
Assert.That(success, Is.False);
Assert.That(error, Does.Contain("UPDATE"));
});
}
#endregion
}