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:
@@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strata.SqlTools.SqlBreakdow
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strata.SqlTools.Query", "src\Strata.SqlTools.Query\Strata.SqlTools.Query.csproj", "{177F3799-6A91-477B-87CC-BCCE05B87E1C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests.Integration", "Tests.Integration", "{CFCF0678-C587-40E9-B0AC-A7082AEBF206}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
using System.Collections;
|
||||
using Strata.SqlTools.SqlBreakdown.Utilities;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.Utilities;
|
||||
|
||||
[TestFixture]
|
||||
public class ArrayUtilsTests
|
||||
{
|
||||
private static readonly Guid GuidA = new("11111111-1111-1111-1111-111111111111");
|
||||
private static readonly Guid GuidB = new("22222222-2222-2222-2222-222222222222");
|
||||
private static readonly Guid GuidC = new("33333333-3333-3333-3333-333333333333");
|
||||
|
||||
#region NewArray / Coalesce
|
||||
|
||||
[Test]
|
||||
public void NewArray_ReturnsArrayOfValues()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.NewArray(1, 2, 3);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { 1, 2, 3 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Coalesce_ReturnsFirstNonNull()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.Coalesce(null!, null!, "x", "y"), Is.EqualTo("x"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Coalesce_AllNull_ReturnsNull()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.Coalesce(null!, null!), Is.Null);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CSV -> Collection
|
||||
|
||||
[Test]
|
||||
public void GetArrayListFromCsv_TrimsAndSplits()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetArrayListFromCsv("a, b, c");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new ArrayList { "a", "b", "c" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetArrayListFromCsv_Empty_ReturnsEmptyList()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetArrayListFromCsv(string.Empty), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGenericListFromCsv_TrimsEntries()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetGenericListFromCsv("a, b ,c");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<string> { "a", "b", "c" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGenericListFromCsv_Empty_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetGenericListFromCsv(string.Empty), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetIntegerListFromCsv_SkipsNonIntegers()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetIntegerListFromCsv("1,2,x,3");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<int> { 1, 2, 3 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidListFromCsv_ParsesValidSkipsInvalid()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetGuidListFromCsv($"{GuidA},not-a-guid,{GuidB}");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<Guid> { GuidA, GuidB }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidListFromCsv_Empty_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetGuidListFromCsv(string.Empty), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidArrayFromCsv_ParsesGuids()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetGuidArrayFromCsv($"{GuidA},{GuidB}");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { GuidA, GuidB }));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Collection -> CSV
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromArrayList_JoinsWithCommas()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetCsvFromArrayList(new ArrayList { "a", "b", "c" });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("a,b,c"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericList_JoinsWithCommas()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetCsvFromGenericList(new List<string> { "a", "b" }), Is.EqualTo("a,b"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericList_SingleQuotes_WrapsEachValue()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetCsvFromGenericList(new List<string> { "a", "b" }, ArrayUtils.QuoteType.Single);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("'a','b'"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericList_DoubleQuotes_WrapsEachValue()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetCsvFromGenericList(new List<string> { "a", "b" }, ArrayUtils.QuoteType.Double);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo("\"a\",\"b\""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericList_NoneQuoteType_BehavesLikePlainJoin()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetCsvFromGenericList(new List<string> { "a", "b" }, ArrayUtils.QuoteType.None), Is.EqualTo("a,b"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericListOfGuids_Null_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetCsvFromGenericListOfGuids(null!), Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericListOfGuids_NoQuotes_JoinsGuids()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetCsvFromGenericListOfGuids(new List<Guid> { GuidA, GuidB });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo($"{GuidA},{GuidB}"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCsvFromGenericListOfGuids_SingleQuotes_WrapsEachGuid()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetCsvFromGenericListOfGuids(new List<Guid> { GuidA }, ArrayUtils.QuoteType.Single);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo($"'{GuidA}'"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Encode
|
||||
|
||||
[Test]
|
||||
public void Encode_NoInternalDelimiters_JoinsWithCommas()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.Encode(new List<string> { "x", "y", "z" }), Is.EqualTo("x,y,z"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Encode_InternalComma_ReplacedWithIllegalCharacter()
|
||||
{
|
||||
// Arrange - internal commas are swapped for char(8) so they survive the comma join
|
||||
const char illegal = (char)8;
|
||||
|
||||
// Act
|
||||
var result = ArrayUtils.Encode(new List<string> { "a,b", "c" });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo($"a{illegal}b,c"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Guid List <-> String
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidStringToList_Empty_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.ConvertGuidStringToList(string.Empty), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidStringToList_ParsesAll()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.ConvertGuidStringToList($"{GuidA},{GuidB}");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<Guid> { GuidA, GuidB }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToGuidArray_ParsesStrings()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.ConvertToGuidArray(new[] { GuidA.ToString(), GuidB.ToString() });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new[] { GuidA, GuidB }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToGuidList_ParsesStrings()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.ConvertToGuidList(new[] { GuidA.ToString() });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<Guid> { GuidA }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidListToString_Null_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.ConvertGuidListToString(null!), Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidListToString_NoSurround_JoinsWithCommas()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.ConvertGuidListToString(new[] { GuidA, GuidB }), Is.EqualTo($"{GuidA},{GuidB}"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidListToString_WithSurroundChar_WrapsEachGuid()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.ConvertGuidListToString(new[] { GuidA }, "'");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo($"'{GuidA}'"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidListToStringList_ReturnsStringRepresentations()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.ConvertGuidListToStringList(new[] { GuidA, GuidB });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<string> { GuidA.ToString(), GuidB.ToString() }));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Intersection
|
||||
|
||||
[Test]
|
||||
public void GetGuidListsIntersection_ReturnsCommonGuids()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetGuidListsIntersection(
|
||||
new List<Guid> { GuidA, GuidB },
|
||||
new List<Guid> { GuidB, GuidC });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(new List<Guid> { GuidB }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidListsIntersection_NoOverlap_ReturnsEmpty()
|
||||
{
|
||||
// Act
|
||||
var result = ArrayUtils.GetGuidListsIntersection(
|
||||
new List<Guid> { GuidA },
|
||||
new List<Guid> { GuidB });
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidListsIntersection_NullArguments_ReturnEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(ArrayUtils.GetGuidListsIntersection(null!, null!), Is.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Utilities;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.Utilities;
|
||||
|
||||
[TestFixture]
|
||||
public class GuidUtilsTests
|
||||
{
|
||||
private static readonly Guid Sample = new("0123abcd-4567-89ef-0123-456789abcdef");
|
||||
|
||||
#region TranslateGuid / UnTranslateGuid
|
||||
|
||||
[Test]
|
||||
public void TranslateGuid_RemovesHyphensAndPrefixesWithG()
|
||||
{
|
||||
// Act
|
||||
var result = GuidUtils.TranslateGuid(Sample);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("g"));
|
||||
Assert.That(result, Has.Length.EqualTo(33));
|
||||
Assert.That(result, Does.Not.Contain("-"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnTranslateGuid_RoundTripsTranslateGuid()
|
||||
{
|
||||
// Arrange
|
||||
var translated = GuidUtils.TranslateGuid(Sample);
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.UnTranslateGuid(translated), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UnTranslateGuid_AlreadyHyphenated_ParsesDirectly()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.UnTranslateGuid(Sample.ToString()), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
[TestCase("")] // null/empty guard
|
||||
[TestCase("notprefixed")] // no hyphen, does not start with 'g'
|
||||
[TestCase("gTOOSHORT")] // starts with 'g' but wrong length (not 33)
|
||||
public void UnTranslateGuid_InvalidInputs_ReturnEmpty(string value)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.UnTranslateGuid(value), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SQL-safe column GUID
|
||||
|
||||
[Test]
|
||||
public void GetSqlColumnSafeGuid_UppercasesAndReplacesHyphens()
|
||||
{
|
||||
// Act
|
||||
var result = GuidUtils.GetSqlColumnSafeGuid(Sample);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("G"));
|
||||
Assert.That(result, Does.Not.Contain("-"));
|
||||
Assert.That(result, Does.Contain("_"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuidFromSqlColumnSafeGuid_RoundTrips()
|
||||
{
|
||||
// Arrange
|
||||
var safe = GuidUtils.GetSqlColumnSafeGuid(Sample);
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuidFromSqlColumnSafeGuid(safe), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region TranslateTextToGuid
|
||||
|
||||
[Test]
|
||||
public void TranslateTextToGuid_IsDeterministic()
|
||||
{
|
||||
// Act & Assert - same input must always yield the same GUID
|
||||
Assert.That(GuidUtils.TranslateTextToGuid("hello world"), Is.EqualTo(GuidUtils.TranslateTextToGuid("hello world")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TranslateTextToGuid_EmptyInput_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.TranslateTextToGuid(string.Empty), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TranslateTextToGuid_DifferentInputs_GenerallyDiffer()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.TranslateTextToGuid("alpha"), Is.Not.EqualTo(GuidUtils.TranslateTextToGuid("beta")));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Validation
|
||||
|
||||
[TestCase("0123abcd-4567-89ef-0123-456789abcdef", true)]
|
||||
[TestCase("not a guid", false)]
|
||||
[TestCase("", false)]
|
||||
public void IsGuid_String_ValidatesCorrectly(string value, bool expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.IsGuid(value), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsGuid_Object_GuidInstance_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.IsGuid((object)Sample), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsGuid_Object_GuidString_ReturnsTrue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.IsGuid((object)Sample.ToString()), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsGuid_Object_NonGuid_ReturnsFalse()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.IsGuid((object)12345), Is.False);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FindFirstGuid / GetGuids
|
||||
|
||||
[Test]
|
||||
public void FindFirstGuid_EmbeddedGuid_ReturnsIt()
|
||||
{
|
||||
// Act
|
||||
var result = GuidUtils.FindFirstGuid($"prefix {Sample} suffix");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FindFirstGuid_NoGuid_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.FindFirstGuid("nothing here"), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuids_ReturnsAllEmbeddedGuids()
|
||||
{
|
||||
// Arrange
|
||||
var second = new Guid("99999999-9999-9999-9999-999999999999");
|
||||
|
||||
// Act
|
||||
var result = GuidUtils.GetGuids($"a {Sample} b {second} c");
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Has.Count.EqualTo(2));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetGuid
|
||||
|
||||
[Test]
|
||||
public void GetGuid_ValidString_ParsesValue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuid(Sample.ToString()), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuid_InvalidString_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuid("nope"), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuid_InvalidString_ReturnsProvidedDefault()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuid("nope", Sample), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuid_NullObject_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuid((object)null!), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetGuid_Object_ParsesToStringValue()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(GuidUtils.GetGuid((object)Sample.ToString()), Is.EqualTo(Sample));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
using System.Data;
|
||||
using Strata.SqlTools.SqlBreakdown.Enums.SQL;
|
||||
using Strata.SqlTools.SqlBreakdown.Utilities;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.Utilities;
|
||||
|
||||
[TestFixture]
|
||||
public class SqlUtilsTests
|
||||
{
|
||||
#region String Manipulation
|
||||
|
||||
[Test]
|
||||
public void StripColumnTableAlias_RemovesTableAliases()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.StripColumnTableAlias("a.Col1, b.Col2"), Is.EqualTo("Col1,Col2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripColumnTableAlias_NoAlias_LeavesColumnUntouched()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.StripColumnTableAlias("MyCol"), Is.EqualTo("MyCol"));
|
||||
}
|
||||
|
||||
[TestCase("O'Brien", "O''Brien")]
|
||||
[TestCase("", "")]
|
||||
[TestCase("clean", "clean")]
|
||||
public void EscapeInvalidCharacter_DoublesSingleQuotes(string input, string expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.EscapeInvalidCharacter(input), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("Col", "[Col]")]
|
||||
[TestCase("[Col]", "[Col]")]
|
||||
[TestCase("[Col", "[Col]")]
|
||||
[TestCase("Col]", "[Col]")]
|
||||
public void AddBrackets_WrapsWhenMissing(string input, string expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.AddBrackets(input), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveBrackets_StripsSquareBrackets()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.RemoveBrackets("[Col]"), Is.EqualTo("Col"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlFriendlyName_RemovesInvalidCharactersByDefault()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlFriendlyName("a.b c"), Is.EqualTo("abc"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlFriendlyName_UsesReplacement()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlFriendlyName("a.b c", "_"), Is.EqualTo("a_b_c"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Object Name Handling
|
||||
|
||||
[Test]
|
||||
public void GetSqlObjectExpression_BuildsBracketedExpression()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlObjectExpression("dbo", "MyTable"), Is.EqualTo("[dbo].[MyTable]"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlObjectExpression_StripsExistingBrackets()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlObjectExpression("[dbo]", "[MyTable]"), Is.EqualTo("[dbo].[MyTable]"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlObjectName_ExtractsObjectPortion()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlObjectName("[dbo].[MyTable]"), Is.EqualTo("MyTable"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlObjectName_NoDot_ReturnsInput()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlObjectName("MyTable"), Is.EqualTo("MyTable"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlObjectName_MultipleDots_Throws()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<NotSupportedException>(() => SqlUtils.GetSqlObjectName("a.b.c"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlSchemaName_ExtractsSchema()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlSchemaName("data.DimClient"), Is.EqualTo("data"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlSchemaName_NoDot_ReturnsDbo()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlSchemaName("DimClient"), Is.EqualTo("dbo"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlSchemaName_MultipleDots_Throws()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<NotSupportedException>(() => SqlUtils.GetSqlSchemaName("a.b.c"));
|
||||
}
|
||||
|
||||
[TestCase("dbo", true)]
|
||||
[TestCase("DBO", true)]
|
||||
[TestCase("data", false)]
|
||||
public void IsDefaultSchema_ChecksAgainstDbo(string schema, bool expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.IsDefaultSchema(schema), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Type Conversions
|
||||
|
||||
[Test]
|
||||
public void GetStringConversionLength_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetStringConversionLength(SqlDataType.Bit), Is.EqualTo(1));
|
||||
Assert.That(SqlUtils.GetStringConversionLength(SqlDataType.Int), Is.EqualTo(int.MaxValue.ToString().Length));
|
||||
Assert.That(SqlUtils.GetStringConversionLength(SqlDataType.UniqueIdentifier), Is.EqualTo(Guid.Empty.ToString().Length));
|
||||
Assert.That(SqlUtils.GetStringConversionLength(SqlDataType.NVarChar), Is.EqualTo(SqlUtils.MAX_NVARCHAR_LENGTH));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertGuidToAlias_ProducesPrefixedUppercaseAlias()
|
||||
{
|
||||
// Arrange
|
||||
var guid = new Guid("0123abcd-4567-89ef-0123-456789abcdef");
|
||||
|
||||
// Act
|
||||
var result = SqlUtils.ConvertGuidToAlias(guid, "p");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(result, Does.StartWith("p"));
|
||||
Assert.That(result, Does.Not.Contain("-"));
|
||||
Assert.That(result, Is.EqualTo("p0123ABCD456789EF0123456789ABCDEF"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsFixedPrecision_DecimalIsNotFixed()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.IsFixedPrecision(SqlDataType.Decimal), Is.False);
|
||||
Assert.That(SqlUtils.IsFixedPrecision(SqlDataType.Int), Is.True);
|
||||
// IsFixedScale mirrors IsFixedPrecision
|
||||
Assert.That(SqlUtils.IsFixedScale(SqlDataType.Decimal), Is.False);
|
||||
Assert.That(SqlUtils.IsFixedScale(SqlDataType.Int), Is.True);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsFixedMaxLength_VariesByType()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.IsFixedMaxLength(SqlDataType.Int), Is.True);
|
||||
Assert.That(SqlUtils.IsFixedMaxLength(SqlDataType.UniqueIdentifier), Is.True);
|
||||
Assert.That(SqlUtils.IsFixedMaxLength(SqlDataType.VarChar), Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFixedScale_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetFixedScale(SqlDataType.DateTime), Is.EqualTo(3));
|
||||
Assert.That(SqlUtils.GetFixedScale(SqlDataType.Money), Is.EqualTo(4));
|
||||
Assert.That(SqlUtils.GetFixedScale(SqlDataType.Int), Is.EqualTo(0));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFixedScale_Decimal_Throws()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<NotImplementedException>(() => SqlUtils.GetFixedScale(SqlDataType.Decimal));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFixedPrecision_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetFixedPrecision(SqlDataType.BigInt), Is.EqualTo(19));
|
||||
Assert.That(SqlUtils.GetFixedPrecision(SqlDataType.Int), Is.EqualTo(10));
|
||||
Assert.That(SqlUtils.GetFixedPrecision(SqlDataType.Bit), Is.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFixedMaxLength_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetFixedMaxLength(SqlDataType.Int), Is.EqualTo(4));
|
||||
Assert.That(SqlUtils.GetFixedMaxLength(SqlDataType.UniqueIdentifier), Is.EqualTo(16));
|
||||
Assert.That(SqlUtils.GetFixedMaxLength(SqlDataType.TinyInt), Is.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetFixedMaxLength_UnsupportedType_Throws()
|
||||
{
|
||||
// Act & Assert - VarChar has no fixed length
|
||||
Assert.Throws<NotImplementedException>(() => SqlUtils.GetFixedMaxLength(SqlDataType.VarChar));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Well-Known SQL Errors
|
||||
|
||||
[Test]
|
||||
public void GetWellKnownSqlError_DuplicateKeyRow_IsUniqueKeyViolation()
|
||||
{
|
||||
// Arrange
|
||||
var ex = new Exception("Cannot insert duplicate key row in object 'dbo.Users'.");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetWellKnownSqlError(ex), Is.EqualTo(SqlUtils.WellKnownSqlError.UniqueKeyViolation));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetWellKnownSqlError_ObjectAlreadyExists_IsDetected()
|
||||
{
|
||||
// Arrange
|
||||
var ex = new Exception("There is already an object named 'Users' in the database.");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetWellKnownSqlError(ex), Is.EqualTo(SqlUtils.WellKnownSqlError.ObjectAlreadyExists));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetWellKnownSqlError_TruncateForeignKey_IsDetected()
|
||||
{
|
||||
// Arrange
|
||||
var ex = new Exception("Cannot truncate table 'dbo.Orders' because it is being referenced by a FOREIGN KEY constraint.");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetWellKnownSqlError(ex), Is.EqualTo(SqlUtils.WellKnownSqlError.TruncateTableForeignKeyReferenceError));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetWellKnownSqlError_UnrecognizedMessage_IsUnknown()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetWellKnownSqlError(new Exception("Something else entirely")), Is.EqualTo(SqlUtils.WellKnownSqlError.Unknown));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data Type Helpers
|
||||
|
||||
[Test]
|
||||
public void GetClientFriendlyDataTypeName_MapsCategories()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetClientFriendlyDataTypeName(SqlDataType.NVarChar), Is.EqualTo("Text"));
|
||||
Assert.That(SqlUtils.GetClientFriendlyDataTypeName(SqlDataType.Int), Is.EqualTo("Whole Number"));
|
||||
Assert.That(SqlUtils.GetClientFriendlyDataTypeName(SqlDataType.Decimal), Is.EqualTo("Decimal"));
|
||||
Assert.That(SqlUtils.GetClientFriendlyDataTypeName(SqlDataType.DateTime), Is.EqualTo("Date"));
|
||||
Assert.That(SqlUtils.GetClientFriendlyDataTypeName(SqlDataType.Money), Is.EqualTo("Dollars"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IdentityColumnTypes_ContainsIntegerTypes()
|
||||
{
|
||||
// Act
|
||||
var types = SqlUtils.IdentityColumnTypes().ToList();
|
||||
|
||||
// Assert
|
||||
Assert.That(types, Is.EquivalentTo(new[]
|
||||
{
|
||||
SqlDataType.BigInt, SqlDataType.TinyInt, SqlDataType.Int, SqlDataType.SmallInt
|
||||
}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetOrderBySqlDirectionString_MapsDirections()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetOrderBySqlDirectionString(SortDirection.Ascending), Is.EqualTo("ASC"));
|
||||
Assert.That(SqlUtils.GetOrderBySqlDirectionString(SortDirection.Descending), Is.EqualTo("DESC"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSimpleDataType_MapsToCategories()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSimpleDataType(SqlDataType.Int), Is.EqualTo(SimpleDataType.Numeric));
|
||||
Assert.That(SqlUtils.GetSimpleDataType(SqlDataType.DateTime), Is.EqualTo(SimpleDataType.Date));
|
||||
Assert.That(SqlUtils.GetSimpleDataType(SqlDataType.Bit), Is.EqualTo(SimpleDataType.Boolean));
|
||||
Assert.That(SqlUtils.GetSimpleDataType(SqlDataType.UniqueIdentifier), Is.EqualTo(SimpleDataType.GUID));
|
||||
Assert.That(SqlUtils.GetSimpleDataType(SqlDataType.NVarChar), Is.EqualTo(SimpleDataType.String));
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase("1", true)]
|
||||
[TestCase("0", true)]
|
||||
[TestCase("yes", true)]
|
||||
[TestCase("no", true)]
|
||||
[TestCase("true", true)]
|
||||
[TestCase("maybe", false)]
|
||||
public void IsStringValueValidForSimpleDataType_Boolean(string value, bool expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.IsStringValueValidForSimpleDataType(SimpleDataType.Boolean, value), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[TestCase("3.14", true)]
|
||||
[TestCase("100", true)]
|
||||
[TestCase("abc", false)]
|
||||
public void IsStringValueValidForSimpleDataType_Numeric(string value, bool expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.IsStringValueValidForSimpleDataType(SimpleDataType.Numeric, value), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsStringValueValidForSimpleDataType_GuidAndString()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.IsStringValueValidForSimpleDataType(SimpleDataType.GUID, Guid.NewGuid().ToString()), Is.True);
|
||||
Assert.That(SqlUtils.IsStringValueValidForSimpleDataType(SimpleDataType.GUID, "nope"), Is.False);
|
||||
// String accepts anything
|
||||
Assert.That(SqlUtils.IsStringValueValidForSimpleDataType(SimpleDataType.String, "anything"), Is.True);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueType_MapsToClrTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetValueType(SqlDataType.Bit), Is.EqualTo(typeof(bool)));
|
||||
Assert.That(SqlUtils.GetValueType(SqlDataType.DateTime), Is.EqualTo(typeof(DateTime)));
|
||||
Assert.That(SqlUtils.GetValueType(SqlDataType.Int), Is.EqualTo(typeof(double)));
|
||||
Assert.That(SqlUtils.GetValueType(SqlDataType.UniqueIdentifier), Is.EqualTo(typeof(Guid)));
|
||||
Assert.That(SqlUtils.GetValueType(SqlDataType.NVarChar), Is.EqualTo(typeof(string)));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlDataType_MapsFromSqlDbType()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSqlDataType(SqlDbType.Int), Is.EqualTo(SqlDataType.Int));
|
||||
Assert.That(SqlUtils.GetSqlDataType(SqlDbType.DateTime2), Is.EqualTo(SqlDataType.DateTime));
|
||||
Assert.That(SqlUtils.GetSqlDataType(SqlDbType.UniqueIdentifier), Is.EqualTo(SqlDataType.UniqueIdentifier));
|
||||
// Unmapped types fall back to NVarChar
|
||||
Assert.That(SqlUtils.GetSqlDataType(SqlDbType.Variant), Is.EqualTo(SqlDataType.NVarChar));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Values
|
||||
|
||||
[Test]
|
||||
public void GetSqlDefaultValueDefinition_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSqlDefaultValueDefinition(SqlDataType.Int), Is.EqualTo("(0)"));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValueDefinition(SqlDataType.VarChar), Is.EqualTo("('')"));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValueDefinition(SqlDataType.DateTime), Is.EqualTo("(getdate())"));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValueDefinition(SqlDataType.UniqueIdentifier), Is.EqualTo($"('{Guid.Empty}')"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlZeroValue_KnownTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSqlZeroValue(SqlDataType.Int), Is.EqualTo(0));
|
||||
Assert.That(SqlUtils.GetSqlZeroValue(SqlDataType.NVarChar), Is.EqualTo(string.Empty));
|
||||
Assert.That(SqlUtils.GetSqlZeroValue(SqlDataType.DateTime), Is.EqualTo(new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Unspecified)));
|
||||
Assert.That(SqlUtils.GetSqlZeroValue(SqlDataType.UniqueIdentifier), Is.EqualTo(Guid.Empty));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlDefaultValue_NullDefinition_ReturnsNull()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.Int, string.Empty), Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlDefaultValue_ParsesScalarTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.Int, "(0)"), Is.EqualTo(0));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.BigInt, "(123)"), Is.EqualTo(123L));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.Bit, "(1)"), Is.EqualTo(true));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.Bit, "(0)"), Is.EqualTo(false));
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.NVarChar, "('hello')"), Is.EqualTo("hello"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlDefaultValue_UniqueIdentifierZeroGuid_ReturnsEmpty()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(SqlUtils.GetSqlDefaultValue(SqlDataType.UniqueIdentifier, "(dbo.ZeroGUID())"), Is.EqualTo(Guid.Empty));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Join / Connection Strings
|
||||
|
||||
[Test]
|
||||
public void GetSqlJoinTypeString_MapsJoinTypes()
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(SqlUtils.GetSqlJoinTypeString(SqlJoinType.Left), Is.EqualTo("LEFT"));
|
||||
Assert.That(SqlUtils.GetSqlJoinTypeString(SqlJoinType.Right), Is.EqualTo("RIGHT"));
|
||||
Assert.That(SqlUtils.GetSqlJoinTypeString(SqlJoinType.Inner), Is.EqualTo("INNER"));
|
||||
Assert.That(SqlUtils.GetSqlJoinTypeString(SqlJoinType.Cross), Is.EqualTo("CROSS"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSqlConnectionString_BuildsIntegratedSecurityConnection()
|
||||
{
|
||||
// Act
|
||||
var result = SqlUtils.GetSqlConnectionString("MyServer", "MyDb");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(result, Does.Contain("data source=MyServer;"));
|
||||
Assert.That(result, Does.Contain("initial catalog=MyDb;"));
|
||||
Assert.That(result, Does.Contain("Integrated Security=SSPI;"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Strata.SqlTools.SqlBreakdown.Utilities;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.Utilities;
|
||||
|
||||
[TestFixture]
|
||||
public class StringUtilsTests
|
||||
{
|
||||
[TestCase('a', -842352705)]
|
||||
[TestCase('z', -842352730)]
|
||||
[TestCase('A', -842352673)]
|
||||
[TestCase('Z', -842352698)]
|
||||
[TestCase('0', -842352768)]
|
||||
[TestCase('9', -842352759)]
|
||||
[TestCase(' ', -842352737)]
|
||||
[TestCase('-', -842352782)]
|
||||
public void GetHashCode32Bit_KnownCharacters_ReturnsHardcodedHash(char c, int expected)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.That(StringUtils.GetHashCode32Bit(c), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetHashCode32Bit_UnmappedCharacter_UsesConsistentFallback()
|
||||
{
|
||||
// Arrange - '!' is not in the hardcoded table
|
||||
const char c = '!';
|
||||
var expected = -842352737 - (int)c;
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(StringUtils.GetHashCode32Bit(c), Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetHashCode32Bit_SameCharacter_IsDeterministic()
|
||||
{
|
||||
// Act & Assert - critical: TranslateTextToGuid relies on stable hashing
|
||||
Assert.That(StringUtils.GetHashCode32Bit('q'), Is.EqualTo(StringUtils.GetHashCode32Bit('q')));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.SqlServer;
|
||||
|
||||
[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.DeleteClause.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
|
||||
var breakdown = new DeleteBreakdown("Users", "Id = @Id");
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("DELETE"));
|
||||
Assert.That(sql, Does.Contain("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"));
|
||||
Assert.That(sql, Does.Not.Contain("WHERE"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithDeleteClause_RendersAlias()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new DeleteBreakdown("Users u", "u.Id = 1")
|
||||
{
|
||||
DeleteClause = { Clause = "u" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("DELETE"));
|
||||
Assert.That(sql, Does.Contain("u"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse Tests
|
||||
|
||||
[Test]
|
||||
public void Parse_SimpleDeleteFrom_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_DeleteWithAlias_PopulatesDeleteAndFromClauses()
|
||||
{
|
||||
// Arrange - DELETE u FROM Users u WHERE ... uses the alias pattern
|
||||
var input = "DELETE u FROM Users u WHERE u.Id = 1";
|
||||
|
||||
// Act
|
||||
var breakdown = DeleteBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.DeleteClause.Clause, Is.EqualTo("u"));
|
||||
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("Users u"));
|
||||
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("u.Id = 1"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_DeleteWithoutWhere_LeavesWhereEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var input = "DELETE FROM Users";
|
||||
|
||||
// Act
|
||||
var breakdown = DeleteBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("Users"));
|
||||
Assert.That(breakdown.IsUsingWhereClause, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[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_WrongPrefix_ReturnsFalseWithMessage()
|
||||
{
|
||||
// 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"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParse_ValidDelete_ReturnsTrue()
|
||||
{
|
||||
// Act
|
||||
var success = DeleteBreakdown.TryParse("DELETE FROM Users WHERE Id = 1", out var breakdown);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.True);
|
||||
Assert.That(breakdown.FromClause.Clause, Is.EqualTo("Users"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.SqlServer;
|
||||
|
||||
[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));
|
||||
Assert.That(breakdown.SetupClauses, Is.Empty);
|
||||
Assert.That(breakdown.FinishClauses, Is.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_WithClauses_ExtractsComments()
|
||||
{
|
||||
// Arrange & Act
|
||||
var breakdown = new InsertBreakdown("Users /* target */", "Id, Name", "@Id, @Name");
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.TableName.Clause, Is.EqualTo("Users"));
|
||||
Assert.That(breakdown.TableName.Comment, Does.Contain("target"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Constructor_WithColumnNames_GeneratesBracketedColumnsAndAtParameters()
|
||||
{
|
||||
// Arrange & Act
|
||||
var breakdown = new InsertBreakdown("Users", new List<string> { "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"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetSql Tests
|
||||
|
||||
[Test]
|
||||
public void GetSql_RendersInsertIntoTableColumnsValues()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new InsertBreakdown("Users", "Id, Name", "@Id, @Name");
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("INSERT INTO"));
|
||||
Assert.That(sql, Does.Contain("Users"));
|
||||
Assert.That(sql, Does.Contain("Id, Name"));
|
||||
Assert.That(sql, Does.Contain("VALUES"));
|
||||
Assert.That(sql, Does.Contain("@Id, @Name"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ToString_ReturnsGeneratedSql()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new InsertBreakdown("Users", "Id", "@Id");
|
||||
|
||||
// Act & Assert
|
||||
Assert.That(breakdown.ToString(), Does.Contain("INSERT INTO"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse Tests
|
||||
|
||||
[Test]
|
||||
public void Parse_ValidInsert_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_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_WrongPrefix_ReturnsFalseWithMessage()
|
||||
{
|
||||
// Act
|
||||
var success = InsertBreakdown.TryParse("UPDATE Users SET Id = 1", out _, out var error);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.False);
|
||||
Assert.That(error, Does.Contain("INSERT INTO"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParse_MalformedInsert_ReturnsFalse()
|
||||
{
|
||||
// Act - matches the INSERT INTO prefix but not the column/values grammar
|
||||
var success = InsertBreakdown.TryParse("INSERT INTO Users", out _, out var error);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.False);
|
||||
Assert.That(error, Is.Not.Null.And.Not.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSql_IncludeSetupFinish_RendersSetupAndFinishClauses()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new InsertBreakdown("Users", "Id", "@Id")
|
||||
{
|
||||
SetupClauses = { "SET NOCOUNT ON" },
|
||||
FinishClauses = { "SELECT SCOPE_IDENTITY()" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var withClauses = breakdown.GetSql(includeSetupFinish: true);
|
||||
var withoutClauses = breakdown.GetSql(includeSetupFinish: false);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(withClauses, Does.Contain("SET NOCOUNT ON"));
|
||||
Assert.That(withClauses, Does.Contain("SELECT SCOPE_IDENTITY()"));
|
||||
Assert.That(withClauses, Does.Contain("INSERT INTO"));
|
||||
Assert.That(withoutClauses, Does.Not.Contain("SET NOCOUNT ON"));
|
||||
Assert.That(withoutClauses, Does.Not.Contain("SELECT SCOPE_IDENTITY()"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.SqlServer;
|
||||
|
||||
[TestFixture]
|
||||
public class ProcedureBreakdownTests
|
||||
{
|
||||
#region Constructor Tests
|
||||
|
||||
[Test]
|
||||
public void Constructor_Default_InitializesEmptyState()
|
||||
{
|
||||
// Arrange & Act
|
||||
var breakdown = new ProcedureBreakdown();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo(string.Empty));
|
||||
Assert.That(breakdown.Parameters, Is.Empty);
|
||||
Assert.That(breakdown.IsUsingParameters, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Constructor_WithName_SetsProcedureName()
|
||||
{
|
||||
// Arrange & Act
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUsers");
|
||||
|
||||
// Assert
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUsers"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Constructor_WithParameters_SetsParameters()
|
||||
{
|
||||
// Arrange
|
||||
var parameters = new Dictionary<string, string> { ["@Id"] = "1" };
|
||||
|
||||
// Act
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUser", parameters);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.IsUsingParameters, Is.True);
|
||||
Assert.That(breakdown.Parameters["@Id"], Is.EqualTo("1"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddParameter Tests
|
||||
|
||||
[Test]
|
||||
public void AddParameter_WithoutAtPrefix_AddsAtPrefix()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUser");
|
||||
|
||||
// Act
|
||||
breakdown.AddParameter("Id", "1");
|
||||
|
||||
// Assert
|
||||
Assert.That(breakdown.Parameters.ContainsKey("@Id"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddParameter_WithAtPrefix_KeepsSinglePrefix()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUser");
|
||||
|
||||
// Act
|
||||
breakdown.AddParameter("@Id", "1");
|
||||
|
||||
// Assert
|
||||
Assert.That(breakdown.Parameters.ContainsKey("@Id"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddParameter_NullName_ThrowsArgumentNullException()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUser");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => breakdown.AddParameter(" ", "1"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetSql Tests
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithoutParameters_RendersExecName()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUsers");
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("EXEC"));
|
||||
Assert.That(sql, Does.Contain("dbo.GetUsers"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithParameters_RendersNamedAssignments()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new ProcedureBreakdown("dbo.GetUser");
|
||||
breakdown.AddParameter("@Id", "1");
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("EXEC"));
|
||||
Assert.That(sql, Does.Contain("@Id = 1"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse Tests
|
||||
|
||||
[Test]
|
||||
public void Parse_ExecWithoutParameters_PopulatesName()
|
||||
{
|
||||
// Arrange
|
||||
var input = "EXEC dbo.GetUsers";
|
||||
|
||||
// Act
|
||||
var breakdown = ProcedureBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUsers"));
|
||||
Assert.That(breakdown.IsUsingParameters, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_ExecWithParameters_PopulatesParameters()
|
||||
{
|
||||
// Arrange
|
||||
var input = "EXEC dbo.GetUser @Id = 1, @Active = 1";
|
||||
|
||||
// Act
|
||||
var breakdown = ProcedureBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUser"));
|
||||
Assert.That(breakdown.Parameters["@Id"], Is.EqualTo("1"));
|
||||
Assert.That(breakdown.Parameters["@Active"], Is.EqualTo("1"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_ExecuteKeyword_IsAccepted()
|
||||
{
|
||||
// Act
|
||||
var breakdown = ProcedureBreakdown.Parse("EXECUTE dbo.GetUsers");
|
||||
|
||||
// Assert
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUsers"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_NullOrWhitespace_ThrowsArgumentNullException()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>(() => ProcedureBreakdown.Parse(" "));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_NotAnExecStatement_ThrowsFormatException()
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Throws<FormatException>(() => ProcedureBreakdown.Parse("SELECT * FROM Users"));
|
||||
}
|
||||
|
||||
[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("EXEC"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParse_ValidExec_ReturnsTrue()
|
||||
{
|
||||
// Act
|
||||
var success = ProcedureBreakdown.TryParse("EXEC dbo.GetUsers", out var breakdown);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.True);
|
||||
Assert.That(breakdown.ProcedureName.Clause, Is.EqualTo("dbo.GetUsers"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
using Strata.SqlTools.Breakdowns.SqlServer;
|
||||
|
||||
namespace Strata.SqlTools.SqlBreakdown.Tests.SqlServer;
|
||||
|
||||
[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.FromClause.Clause, Is.EqualTo(string.Empty));
|
||||
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo(string.Empty));
|
||||
Assert.That(breakdown.IsUsingFromClause, Is.False);
|
||||
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"));
|
||||
Assert.That(breakdown.IsUsingWhereClause, Is.True);
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetSql Tests
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithWhere_RendersUpdateSetWhere()
|
||||
{
|
||||
// Arrange
|
||||
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"));
|
||||
Assert.That(sql, Does.Contain("Id = @Id"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithoutWhere_OmitsWhereKeyword()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new UpdateBreakdown("Users", "Name = @Name", string.Empty);
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(sql, Does.Contain("UPDATE"));
|
||||
Assert.That(sql, Does.Not.Contain("WHERE"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSql_WithFromClause_RendersFromSection()
|
||||
{
|
||||
// Arrange
|
||||
var breakdown = new UpdateBreakdown("u", "u.Name = s.Name", "u.Id = s.Id")
|
||||
{
|
||||
FromClause = { Clause = "Users u INNER JOIN Staging s ON u.Id = s.Id" }
|
||||
};
|
||||
|
||||
// Act
|
||||
var sql = breakdown.GetSql();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.IsUsingFromClause, Is.True);
|
||||
Assert.That(sql, Does.Contain("FROM"));
|
||||
Assert.That(sql, Does.Contain("INNER JOIN Staging"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parse Tests
|
||||
|
||||
[Test]
|
||||
public void Parse_SimpleUpdate_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 u SET u.Name = s.Name FROM Users u INNER JOIN Staging s ON u.Id = s.Id WHERE s.Active = 1";
|
||||
|
||||
// Act
|
||||
var breakdown = UpdateBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.TableName.Clause, Is.EqualTo("u"));
|
||||
Assert.That(breakdown.IsUsingFromClause, Is.True);
|
||||
Assert.That(breakdown.FromClause.Clause, Does.Contain("INNER JOIN Staging"));
|
||||
Assert.That(breakdown.WhereClause.Clause, Is.EqualTo("s.Active = 1"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_UpdateWithoutWhere_LeavesWhereEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var input = "UPDATE Users SET Name = 'Bob'";
|
||||
|
||||
// Act
|
||||
var breakdown = UpdateBreakdown.Parse(input);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(breakdown.SetClause.Clause, Is.EqualTo("Name = 'Bob'"));
|
||||
Assert.That(breakdown.IsUsingWhereClause, Is.False);
|
||||
});
|
||||
}
|
||||
|
||||
[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("DELETE FROM Users"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParse_WrongPrefix_ReturnsFalseWithMessage()
|
||||
{
|
||||
// Act
|
||||
var success = UpdateBreakdown.TryParse("SELECT * FROM Users", out _, out var error);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.False);
|
||||
Assert.That(error, Does.Contain("UPDATE"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryParse_ValidUpdate_ReturnsTrue()
|
||||
{
|
||||
// Act
|
||||
var success = UpdateBreakdown.TryParse("UPDATE Users SET Name = 'Bob' WHERE Id = 1", out var breakdown);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// Assert
|
||||
Assert.That(success, Is.True);
|
||||
Assert.That(breakdown.TableName.Clause, Is.EqualTo("Users"));
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user